Merge "Output XML CTS Coverage report" into kitkat-cts-dev am: f2ce5cef21 am: 301c38ce5d am: eb9de0da37 am: 83e8bb882f am: 6ae1feff50 am: 154f7beab9 am: 4c82cddab2 am: fe9f8f073f am: b1802565d7
am: 72eb395cdb

* commit '72eb395cdbf475cad3ac90f69fc6b2c9274c2de5':
  Output XML CTS Coverage report
diff --git a/CtsBuild.mk b/CtsBuild.mk
index ba158ce..c745885 100644
--- a/CtsBuild.mk
+++ b/CtsBuild.mk
@@ -40,10 +40,6 @@
 	$(foreach executable,$(1),$(CTS_TESTCASES_OUT)/$(executable))
 endef
 
-define cts-get-deqp-api-test-xmls
-	$(foreach file,$(call find-files-in-subdirs, external/deqp/android/cts/master, 'com.drawelements.deqp.$(1).*xml', .),$(CTS_TESTCASES_OUT)/$(file))
-endef
-
 define cts-get-deqp-test-xmls
-	$(foreach api,$(1),$(call cts-get-deqp-api-test-xmls,$(api)))
+	$(foreach api,$(1),$(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(api).xml)
 endef
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 4470478..f239326 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -72,31 +72,29 @@
     CtsUnaffiliatedAccountAuthenticators
 
 cts_support_packages := \
-    CtsAccelerationTestStubs \
     CtsAlarmClockService \
     CtsAppTestStubs \
+    CtsAppUsageTestApp \
     CtsAssistService \
     CtsAssistApp \
     CtsAtraceTestApp \
     CtsCertInstallerApp \
-    CtsDeviceAdmin \
-    CtsDeviceOpenGl \
+    CtsAdminApp \
     CtsWifiConfigCreator \
     CtsDeviceAndProfileOwnerApp \
-    CtsDeviceAppUsageTestApp \
     CtsDeviceInfo \
     CtsDeviceOsTestApp \
     CtsDeviceOwnerApp \
-    CtsDeviceTaskswitchingAppA \
-    CtsDeviceTaskswitchingAppB \
-    CtsDeviceTaskswitchingControl \
-    CtsDeviceUi \
+    CtsDeviceServicesTestApp \
+    CtsDeviceTaskSwitchingAppA \
+    CtsDeviceTaskSwitchingAppB \
+    CtsDeviceTaskSwitchingControl \
     CtsHostsideNetworkTestsApp \
     CtsIntentReceiverApp \
     CtsIntentSenderApp \
     CtsLauncherAppsTests \
     CtsLauncherAppsTestsSupport \
-    CtsLeanbackJank \
+    CtsLeanbackJankApp \
     CtsManagedProfileApp \
     CtsMonkeyApp \
     CtsMonkeyApp2 \
@@ -107,7 +105,7 @@
     CtsSomeAccessibilityServices \
     CtsThemeDeviceApp \
     TestDeviceSetup \
-    CtsUiAutomatorApp \
+    CtsUiAutomatorTestApp \
     CtsUsbSerialTestApp \
     CtsVoiceInteractionService \
     CtsVoiceInteractionApp \
@@ -129,14 +127,7 @@
 
 # Test packages that require an associated test package XML.
 cts_test_packages := \
-    CtsDeviceFilePerf \
-    CtsDeviceUi \
-    CtsDeviceDram \
-    CtsDeviceSimpleCpu \
-    CtsDeviceBrowserBench \
-    CtsDeviceVideoPerf \
-    CtsDeviceOpenGl \
-    CtsDeviceTvProviderPerf \
+    CtsIcuTestCases \
     CtsAccelerationTestCases \
     CtsAccountManagerTestCases \
     CtsAccessibilityServiceTestCases \
@@ -148,6 +139,7 @@
     CtsAppWidgetTestCases \
     CtsAssistTestCases \
     CtsBluetoothTestCases \
+    CtsBrowserTestCases \
     CtsCalendarcommon2TestCases \
     CtsCallLogTestCases \
     CtsCameraTestCases \
@@ -156,31 +148,32 @@
     CtsDisplayTestCases \
     CtsDpiTestCases \
     CtsDpiTestCases2 \
+    CtsDramTestCases \
     CtsDreamsTestCases \
     CtsDrmTestCases \
     CtsEffectTestCases \
+    CtsFileSystemTestCases \
     CtsGestureTestCases \
     CtsGraphicsTestCases \
     CtsGraphics2TestCases \
     CtsHardwareTestCases \
-    CtsJankTestCases \
+    CtsJankDeviceTestCases \
     CtsLeanbackJankTestCases \
-    CtsJobSchedulerDeviceTestCases \
+    CtsJobSchedulerTestCases \
     CtsJniTestCases \
     CtsKeystoreTestCases \
     CtsLibcoreLegacy22TestCases \
     CtsLocationTestCases \
     CtsLocation2TestCases \
     CtsMediaStressTestCases \
-    CtsMediaTestCases \
     CtsMidiTestCases \
-    CtsNativeOpenGLTestCases \
     CtsNdefTestCases \
     CtsNetTestCases \
     CtsNetTestCasesLegacyApi22 \
     CtsNetTestCasesLegacyPermission22 \
     CtsOpenGLTestCases \
     CtsOpenGlPerfTestCases \
+    CtsOpenGlPerf2TestCases \
     CtsOsTestCases \
     CtsPermissionTestCases \
     CtsPermission2TestCases \
@@ -195,6 +188,7 @@
     CtsSaxTestCases \
     CtsSecurityTestCases \
     CtsSignatureTestCases \
+    CtsSimpleCpuTestCases \
     CtsSpeechTestCases \
     CtsSystemUiTestCases \
     CtsTelecomTestCases \
@@ -202,13 +196,16 @@
     CtsTelephonyTestCases \
     CtsTextTestCases \
     CtsTextureViewTestCases \
-    CtsThemeTestCases \
+    CtsThemeDeviceTestCases \
     CtsTransitionTestCases \
+    CtsTvProviderTestCases \
     CtsTvTestCases \
     CtsUiAutomationTestCases \
     CtsUiRenderingTestCases \
+    CtsUiDeviceTestCases \
     CtsUsageStatsTestCases \
     CtsUtilTestCases \
+    CtsVideoTestCases \
     CtsViewTestCases \
     CtsVoiceInteractionTestCases \
     CtsVoiceSettingsTestCases \
@@ -222,20 +219,21 @@
 
 # Host side only tests
 cts_host_libraries := \
-    CtsAdbTests \
-    CtsAppSecurityTests \
+    CtsAadbHostTestCases \
+    CtsAppSecurityHostTestCases \
+    CtsAppUsageHostTestCases \
     CtsAtraceHostTestCases \
     CtsDevicePolicyManagerTestCases \
     CtsDumpsysHostTestCases \
-    CtsHostJank \
+    CtsJankHostTestCases \
     CtsHostsideNetworkTests \
-    CtsHostUi \
     CtsJdwpSecurityHostTestCases \
     CtsMonkeyTestCases \
     CtsOsHostTestCases \
-    CtsThemeHostTestCases \
-    CtsUsageHostTestCases \
     CtsSecurityHostTestCases \
+    CtsServicesHostTestCases \
+    CtsThemeHostTestCases \
+    CtsUiHostTestCases \
     CtsUsbTests
 
 # List of native tests. For 32 bit targets, assumes that there will be
@@ -243,18 +241,18 @@
 # 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 \
+    CtsNativeMediaSlTestCases \
+    CtsNativeMediaXaTestCases \
 
 ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
-cts_native_tests += bionic-unit-tests-cts
+cts_native_tests += CtsBionicTestCases
 endif
 
 cts_ui_tests := \
-    CtsUiAutomatorTests
+    CtsUiAutomatorTestCases
 
 cts_device_jars := \
-    CtsDeviceJank \
+    CtsJankTestJar \
     CtsJdwpApp
 
 cts_target_junit_tests := \
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index cb525c8..2d8f6a9 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -27,7 +27,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-ex-camera2 \
                                android-support-v4 \
-                               compatibility-common-util-devicesidelib_v2 \
+                               compatibility-common-util-devicesidelib \
                                cts-sensors-tests \
                                ctstestrunner \
                                apache-commons-math \
@@ -37,7 +37,7 @@
                                android-support-v4  \
                                mockito-target \
                                mockwebserver \
-                               compatibility-device-util_v2 \
+                               compatibility-device-util \
 
 LOCAL_PACKAGE_NAME := CtsVerifier
 
@@ -73,8 +73,8 @@
     $(call all-Iaidl-files-under, src)
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 \
-                               compatibility-common-util-devicesidelib_v2 \
-                               compatibility-device-util_v2 \
+                               compatibility-common-util-devicesidelib \
+                               compatibility-device-util \
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index cca46ca..7d106a6 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -58,6 +58,7 @@
     <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
     <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
     <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
+    <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
 
     <!-- Needed by the Audio Quality Verifier to store the sound samples that will be mailed. -->
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -1076,6 +1077,15 @@
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
         </activity>
 
+        <activity android:name=".notifications.ConditionProviderVerifierActivity"
+                  android:label="@string/cp_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>
+
         <activity android:name=".notifications.AttentionManagementVerifierActivity"
                 android:label="@string/attention_test">
             <intent-filter>
@@ -1107,6 +1117,15 @@
             </intent-filter>
         </service>
 
+        <service android:name=".notifications.MockConditionProvider"
+                 android:exported="true"
+                 android:label="@string/cp_service_name"
+                 android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.notification.ConditionProviderService" />
+            </intent-filter>
+        </service>
+
         <service  android:name=".notifications.InteractiveVerifierActivity$DismissService"/>
 
         <activity android:name=".security.CAInstallNotificationVerifierActivity"
diff --git a/apps/CtsVerifier/proguard.flags b/apps/CtsVerifier/proguard.flags
index 5a2beb5..591d3db 100644
--- a/apps/CtsVerifier/proguard.flags
+++ b/apps/CtsVerifier/proguard.flags
@@ -27,3 +27,10 @@
 -dontwarn java.util.concurrent.ConcurrentLinkedDeque
 -dontwarn android.cts.util.**
 -dontwarn junit.**
+
+# Jack seems less rigorous than proguard when it comes to warning about
+# transitive dependencies.
+-dontwarn com.android.org.bouncycastle.**
+-dontwarn com.android.okhttp.**
+-dontwarn org.opencv.**
+-dontwarn android.support.test.internal.runner.hidden.ExposedInstrumentationApi
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 985767c..0560c1c 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1150,6 +1150,23 @@
     <string name="nls_clear_all">Check that service can clear all notifications.</string>
     <string name="nls_service_stopped">Service should stop once disabled.</string>
     <string name="nls_note_missed">Check that notification was not received.</string>
+    <string name="cp_test">Condition Provider test</string>
+    <string name="cp_service_name">Condition Provider for CTS Verifier</string>
+    <string name="cp_info">This test checks that a ConditionProviderService can be enabled
+        and disabled, and that once enabled the service is able to create, query, edit, and delete
+        automatic zen rules.
+    </string>
+    <string name="cp_enable_service">Please enable \"CTS Verifier\" under Do Not Disturb access and return here.</string>
+    <string name="cp_disable_service">Please disable \"CTS Verifier\" under Do Not Disturb access and return here.</string>
+    <string name="cp_start_settings">Launch Settings</string>
+    <string name="cp_create_rule">Creating Automatic Zen Rule</string>
+    <string name="cp_subscribe_rule">Subscribing to Automatic Zen Rule</string>
+    <string name="cp_service_started">Service should start once enabled.</string>
+    <string name="cp_service_stopped">Service should stop once disabled.</string>
+    <string name="cp_unsubscribe_rule">Unsubscribing to Automatic Zen Rule</string>
+    <string name="cp_delete_rule">Deleting Automatic Zen Rule</string>
+    <string name="cp_get_rules">Retrieving Automatic Zen Rules</string>
+    <string name="cp_get_rule">Retrieving Automatic Zen Rule</string>
 
     <string name="location_mode_high_accuracy_test">High Accuracy Mode Test</string>
     <string name="location_mode_high_accuracy_info">
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index dc2502c..76eb8a1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -16,17 +16,17 @@
 
 package com.android.cts.verifier;
 
+import android.content.Context;
+import android.os.Build;
+import android.text.TextUtils;
+import android.util.Xml;
+
 import com.android.compatibility.common.util.MetricsXmlSerializer;
 import com.android.compatibility.common.util.ReportLog;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
 
 import org.xmlpull.v1.XmlSerializer;
 
-import android.content.Context;
-import android.os.Build;
-import android.text.TextUtils;
-import android.util.Xml;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.text.DateFormat;
@@ -130,6 +130,7 @@
                     xml.endTag(null, TEST_DETAILS_TAG);
                 }
 
+                // TODO(stuartscott): For v2: ReportLog.serialize(xml, mAdapter.getReportLog(i));
                 ReportLog reportLog = mAdapter.getReportLog(i);
                 if (reportLog != null) {
                     MetricsXmlSerializer metricsXmlSerializer = new MetricsXmlSerializer(xml);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
index 3c0955d..5dac13b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.verifier.managedprovisioning;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.Intent;
 import android.database.DataSetObserver;
 import android.os.Bundle;
@@ -33,10 +34,8 @@
  */
 public class DeviceOwnerNegativeTestActivity 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);
+            new Intent(DevicePolicyManager.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(
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
index 21c7331..58a1fef 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
@@ -148,7 +148,6 @@
         if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
             forwardedIntentsFromManaged.addAll(Arrays.asList(
                     new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")),
-                    new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")),
                     new Intent("android.intent.action.CALL_EMERGENCY").setData(
                             Uri.parse("tel:123")),
                     new Intent("android.intent.action.CALL_PRIVILEGED").setData(
@@ -174,6 +173,8 @@
                             Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory(
                             Intent.CATEGORY_BROWSABLE),
                     new Intent(Settings.ACTION_APN_SETTINGS)));
+            notForwardedIntentsFromManaged
+                    .add(new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")));
         }
 
         if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
new file mode 100644
index 0000000..47a928c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2015 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 com.android.cts.verifier.R;
+
+import android.app.AutomaticZenRule;
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Parcelable;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ConditionProviderVerifierActivity extends InteractiveVerifierActivity
+        implements Runnable {
+    protected static final String CP_PACKAGE = "com.android.cts.verifier";
+    protected static final String CP_PATH = CP_PACKAGE +
+            "/com.android.cts.verifier.notifications.MockConditionProvider";
+
+    @Override
+    int getTitleResource() {
+        return R.string.cp_test;
+    }
+
+    @Override
+    int getInstructionsResource() {
+        return R.string.cp_info;
+    }
+
+    // Test Setup
+
+    @Override
+    protected List<InteractiveTestCase> createTestItems() {
+        List<InteractiveTestCase> tests = new ArrayList<>(9);
+        tests.add(new IsEnabledTest());
+        tests.add(new ServiceStartedTest());
+        tests.add(new CreateAutomaticZenRuleTest());
+        tests.add(new GetAutomaticZenRuleTest());
+        tests.add(new GetAutomaticZenRulesTest());
+        tests.add(new SubscribeAutomaticZenRuleTest());
+        tests.add(new DeleteAutomaticZenRuleTest());
+        tests.add(new UnsubscribeAutomaticZenRuleTest());
+        tests.add(new IsDisabledTest());
+        tests.add(new ServiceStoppedTest());
+        return tests;
+    }
+
+    protected class IsEnabledTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createSettingsItem(parent, R.string.cp_enable_service);
+        }
+
+        @Override
+        boolean autoStart() {
+            return true;
+        }
+
+        @Override
+        void test() {
+            Intent settings = new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
+            if (settings.resolveActivity(mPackageManager) == null) {
+                logFail("no settings activity");
+                status = FAIL;
+            } else {
+                String cpPackages = Secure.getString(getContentResolver(),
+                        Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+                if (cpPackages != null && cpPackages.contains(CP_PACKAGE)) {
+                    status = PASS;
+                } else {
+                    status = WAIT_FOR_USER;
+                }
+                next();
+            }
+        }
+
+        void tearDown() {
+            // wait for the service to start
+            delay();
+        }
+    }
+
+    protected class ServiceStartedTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.cp_service_started);
+        }
+
+        @Override
+        void test() {
+            MockConditionProvider.probeConnected(mContext,
+                    new MockConditionProvider.BooleanResultCatcher() {
+                        @Override
+                        public void accept(boolean result) {
+                            if (result) {
+                                status = PASS;
+                            } else {
+                                logFail();
+                                status = RETEST;
+                                delay();
+                            }
+                            next();
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            MockConditionProvider.resetData(mContext);
+            delay();
+        }
+    }
+
+    private class CreateAutomaticZenRuleTest extends InteractiveTestCase {
+        private String id = null;
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.cp_create_rule);
+        }
+
+        @Override
+        void test() {
+            long now = System.currentTimeMillis();
+            AutomaticZenRule ruleToCreate =
+                    createRule("Rule", "value", NotificationManager.INTERRUPTION_FILTER_ALARMS);
+            AutomaticZenRule createdRule = mNm.addAutomaticZenRule(ruleToCreate);
+
+            if (createdRule != null
+                    && ruleToCreate.getName().equals(createdRule.getName())
+                    && ruleToCreate.getOwner().equals(createdRule.getOwner())
+                    && ruleToCreate.getConditionId().equals(createdRule.getConditionId())
+                    && ruleToCreate.isEnabled() == createdRule.isEnabled()
+                    && !TextUtils.isEmpty(createdRule.getId())
+                    && createdRule.getCreationTime() > now) {
+                id = createdRule.getId();
+                status = PASS;
+            } else {
+                logFail();
+                status = FAIL;
+            }
+            next();
+        }
+
+        @Override
+        void tearDown() {
+            if (id != null) {
+                mNm.removeAutomaticZenRule(id);
+            }
+            MockConditionProvider.resetData(mContext);
+            delay();
+        }
+    }
+
+    private class SubscribeAutomaticZenRuleTest extends InteractiveTestCase {
+        private String id = null;
+        private AutomaticZenRule ruleToCreate;
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.cp_subscribe_rule);
+        }
+
+        @Override
+        void setUp() {
+            ruleToCreate = createRule("RuleSubscribe", "Subscribevalue",
+                    NotificationManager.INTERRUPTION_FILTER_ALARMS);
+            AutomaticZenRule createdRule = mNm.addAutomaticZenRule(ruleToCreate);
+            id = createdRule == null ? null : createdRule.getId();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+
+            MockConditionProvider.probeSubscribe(mContext,
+                    new MockConditionProvider.ParcelableListResultCatcher() {
+                        @Override
+                        public void accept(List<Parcelable> result) {
+                            boolean foundMatch = false;
+                            for (Parcelable p : result) {
+                                Uri uri = (Uri) p;
+                                if (ruleToCreate.getConditionId().equals(uri)) {
+                                    foundMatch = true;
+                                    break;
+                                }
+                            }
+                            if (foundMatch) {
+                                status = PASS;
+                            } else {
+                                logFail();
+                                status = RETEST;
+                            }
+                            next();
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            if (id != null) {
+                mNm.removeAutomaticZenRule(id);
+            }
+            MockConditionProvider.resetData(mContext);
+            // wait for intent to move through the system
+            delay();
+        }
+    }
+
+    private class GetAutomaticZenRuleTest extends InteractiveTestCase {
+        private String id = null;
+        private AutomaticZenRule ruleToCreate;
+        private AutomaticZenRule createdRule;
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.cp_get_rule);
+        }
+
+        @Override
+        void setUp() {
+            ruleToCreate = createRule("RuleGet", "valueGet",
+                    NotificationManager.INTERRUPTION_FILTER_ALARMS);
+            createdRule = mNm.addAutomaticZenRule(ruleToCreate);
+            id = createdRule == null ? null : createdRule.getId();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (createdRule != null) {
+                id = createdRule.getId();
+                AutomaticZenRule queriedRule = mNm.getAutomaticZenRule(id);
+                if (queriedRule != null
+                        && ruleToCreate.getName().equals(queriedRule.getName())
+                        && ruleToCreate.getOwner().equals(queriedRule.getOwner())
+                        && ruleToCreate.getConditionId().equals(queriedRule.getConditionId())
+                        && ruleToCreate.isEnabled() == queriedRule.isEnabled()
+                        && queriedRule.getId().equals(id)
+                        && createdRule.getCreationTime() == queriedRule.getCreationTime()) {
+                    status = PASS;
+                } else {
+                    logFail();
+                    status = FAIL;
+                }
+            } else {
+                logFail();
+                status = FAIL;
+            }
+            next();
+        }
+
+        @Override
+        void tearDown() {
+            if (id != null) {
+                mNm.removeAutomaticZenRule(id);
+            }
+            MockConditionProvider.resetData(mContext);
+            delay();
+        }
+    }
+
+    private class GetAutomaticZenRulesTest extends InteractiveTestCase {
+        private List<String> ids = new ArrayList<>();
+        AutomaticZenRule createdRule1;
+        AutomaticZenRule createdRule2;
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.cp_get_rules);
+        }
+
+        @Override
+        void setUp() {
+            AutomaticZenRule rule1 =
+                    createRule("Rule1", "value1", NotificationManager.INTERRUPTION_FILTER_ALARMS);
+            AutomaticZenRule rule2 =
+                    createRule("Rule2", "value2", NotificationManager.INTERRUPTION_FILTER_NONE);
+            createdRule1 = mNm.addAutomaticZenRule(rule1);
+            createdRule2 = mNm.addAutomaticZenRule(rule2);
+            ids.add(createdRule1.getId());
+            ids.add(createdRule2.getId());
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            List<AutomaticZenRule> rules = mNm.getAutomaticZenRules();
+
+            if (rules == null || rules.size() < 2) {
+                logFail();
+                status = FAIL;
+                next();
+                return;
+            }
+
+            if (rules.contains(createdRule1) && rules.contains(createdRule2)) {
+                status = PASS;
+            } else {
+                logFail();
+                status = FAIL;
+            }
+            next();
+        }
+
+        @Override
+        void tearDown() {
+            for (String id : ids) {
+                mNm.removeAutomaticZenRule(id);
+            }
+            MockConditionProvider.resetData(mContext);
+            delay();
+        }
+    }
+
+    private class DeleteAutomaticZenRuleTest extends InteractiveTestCase {
+        private String id = null;
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.cp_delete_rule);
+        }
+
+        @Override
+        void test() {
+            AutomaticZenRule ruleToCreate = createRule("RuleDelete", "Deletevalue",
+                    NotificationManager.INTERRUPTION_FILTER_ALARMS);
+            AutomaticZenRule createdRule = mNm.addAutomaticZenRule(ruleToCreate);
+
+            if (createdRule != null) {
+                id = createdRule.getId();
+                if (mNm.removeAutomaticZenRule(id)) {
+                    if (mNm.getAutomaticZenRule(id) == null) {
+                        status = PASS;
+                    } else {
+                        logFail();
+                        status = FAIL;
+                    }
+                } else {
+                    logFail();
+                    status = FAIL;
+                }
+            } else {
+                logFail("Couldn't test rule deletion; creation failed.");
+                status = FAIL;
+            }
+            next();
+        }
+
+        @Override
+        void tearDown() {
+            MockConditionProvider.resetData(mContext);
+            delay();
+        }
+    }
+
+    private class UnsubscribeAutomaticZenRuleTest extends InteractiveTestCase {
+        private String id = null;
+        private AutomaticZenRule ruleToCreate;
+        private AutomaticZenRule createdRule;
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.cp_unsubscribe_rule);
+        }
+
+        @Override
+        void setUp() {
+            ruleToCreate = createRule("RuleUnsubscribe", "valueUnsubscribe",
+                    NotificationManager.INTERRUPTION_FILTER_PRIORITY);
+            createdRule = mNm.addAutomaticZenRule(ruleToCreate);
+            id = createdRule == null ? null : createdRule.getId();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            MockConditionProvider.probeSubscribe(mContext,
+                    new MockConditionProvider.ParcelableListResultCatcher() {
+                        @Override
+                        public void accept(List<Parcelable> result) {
+                            boolean foundMatch = false;
+                            for (Parcelable p : result) {
+                                Uri uri = (Uri) p;
+                                if (ruleToCreate.getConditionId().equals(uri)) {
+                                    foundMatch = true;
+                                    break;
+                                }
+                            }
+                            if (foundMatch) {
+                                // Now that it's subscribed, remove the rule and verify that it
+                                // unsubscribes.
+                                mNm.removeAutomaticZenRule(id);
+                                MockConditionProvider.probeSubscribe(mContext,
+                                        new MockConditionProvider.ParcelableListResultCatcher() {
+                                            @Override
+                                            public void accept(List<Parcelable> result) {
+                                                boolean foundMatch = false;
+                                                for (Parcelable p : result) {
+                                                    Uri uri = (Uri) p;
+                                                    if (ruleToCreate.getConditionId().equals(uri)) {
+                                                        foundMatch = true;
+                                                        break;
+                                                    }
+                                                }
+                                                if (foundMatch) {
+                                                    logFail();
+                                                    status = RETEST;
+                                                } else {
+                                                    status = PASS;
+                                                }
+                                                next();
+                                            }
+                                        });
+                            } else {
+                                logFail("Couldn't test unsubscribe; subscribe failed.");
+                                status = RETEST;
+                                next();
+                            }
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            mNm.removeAutomaticZenRule(id);
+            MockConditionProvider.resetData(mContext);
+            // wait for intent to move through the system
+            delay();
+        }
+    }
+
+    private class IsDisabledTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createSettingsItem(parent, R.string.cp_disable_service);
+        }
+
+        @Override
+        boolean autoStart() {
+            return true;
+        }
+
+        @Override
+        void test() {
+            String cpPackages = Secure.getString(getContentResolver(),
+                    Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+            if (cpPackages == null || !cpPackages.contains(CP_PACKAGE)) {
+                status = PASS;
+            } else {
+                status = WAIT_FOR_USER;
+            }
+            next();
+        }
+
+        @Override
+        void tearDown() {
+            MockConditionProvider.resetData(mContext);
+            delay();
+        }
+    }
+
+    private class ServiceStoppedTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.cp_service_stopped);
+        }
+
+        @Override
+        void test() {
+            MockConditionProvider.probeConnected(mContext,
+                    new MockConditionProvider.BooleanResultCatcher() {
+                        @Override
+                        public void accept(boolean result) {
+                            if (result) {
+                                logFail();
+                                status = RETEST;
+                                delay();
+                            } else {
+                                status = PASS;
+                            }
+                            next();
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            MockConditionProvider.resetData(mContext);
+            // wait for intent to move through the system
+            delay();
+        }
+    }
+
+    private AutomaticZenRule createRule(String name, String queryValue, int status) {
+        return new AutomaticZenRule(name,
+                ComponentName.unflattenFromString(CP_PATH),
+                MockConditionProvider.toConditionId(queryValue),
+                status,
+                true);
+    }
+
+    protected View createSettingsItem(ViewGroup parent, int messageId) {
+        return createUserItem(parent, R.string.cp_start_settings, messageId);
+    }
+
+    public void launchSettings() {
+        startActivity(new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS));
+    }
+
+    public void actionPressed(View v) {
+        Object tag = v.getTag();
+        if (tag instanceof Integer) {
+            int id = ((Integer) tag).intValue();
+            if (id == R.string.cp_start_settings) {
+                launchSettings();
+            } else if (id == R.string.attention_ready) {
+                mCurrentTest.status = READY;
+                next();
+            }
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockConditionProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockConditionProvider.java
new file mode 100644
index 0000000..4b90d9a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockConditionProvider.java
@@ -0,0 +1,192 @@
+/*
+ * 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.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MockConditionProvider extends ConditionProviderService {
+    static final String TAG = "MockConditionProvider";
+
+    static final String PACKAGE_NAME = "com.android.cts.verifier.notifications";
+    static final String PATH = "mock_cp";
+    static final String QUERY = "query_item";
+
+    static final String SERVICE_BASE = "android.service.notification.cts.MockConditionProvider.";
+    static final String SERVICE_CHECK = SERVICE_BASE + "SERVICE_CHECK";
+    static final String SERVICE_RESET = SERVICE_BASE + "SERVICE_RESET";
+    static final String SERVICE_SUBSCRIBE = SERVICE_BASE + "SERVICE_SUBSCRIBE";
+
+    static final String EXTRA_PAYLOAD = "PAYLOAD";
+    static final String EXTRA_INT = "INT";
+    static final String EXTRA_BOOLEAN = "BOOLEAN";
+    static final String EXTRA_TAG = "TAG";
+    static final String EXTRA_CODE = "CODE";
+
+    static final int RESULT_NO_SERVER = Activity.RESULT_FIRST_USER + 1;
+
+
+    private ArrayList<Uri> mSubscriptions = new ArrayList<>();
+    private boolean mConnected = false;
+    private BroadcastReceiver mReceiver;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.d(TAG, "created");
+
+        mSubscriptions = new ArrayList<Uri>();
+
+        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");
+                    Bundle bundle = new Bundle();
+                    bundle.putBoolean(EXTRA_BOOLEAN, mConnected);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_SUBSCRIBE.equals(action)) {
+                    Log.d(TAG, "SERVICE_SUBSCRIBE");
+                    Bundle bundle = new Bundle();
+                    bundle.putParcelableArrayList(EXTRA_PAYLOAD, mSubscriptions);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } 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_SUBSCRIBE);
+        filter.addAction(SERVICE_RESET);
+        registerReceiver(mReceiver, filter);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mConnected = false;
+        unregisterReceiver(mReceiver);
+        mReceiver = null;
+        Log.d(TAG, "destroyed");
+    }
+
+    public void resetData() {
+        mSubscriptions.clear();
+    }
+
+    public static void resetData(Context context) {
+        sendCommand(context, SERVICE_RESET, null, 0);
+    }
+
+    public static void probeConnected(Context context, BooleanResultCatcher catcher) {
+        requestConnected(context, SERVICE_CHECK, catcher);
+    }
+
+    public static void probeSubscribe(Context context, ParcelableListResultCatcher catcher) {
+        requestParcelableListResult(context, SERVICE_SUBSCRIBE, catcher);
+    }
+
+    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 static Uri toConditionId(String queryValue) {
+        return new Uri.Builder().scheme(Condition.SCHEME)
+                .authority(PACKAGE_NAME)
+                .appendPath(PATH)
+                .appendQueryParameter(QUERY, queryValue)
+                .build();
+    }
+
+    @Override
+    public void onConnected() {
+        Log.d(TAG, "connected");
+        mConnected = true;
+    }
+
+    @Override
+    public void onRequestConditions(int relevance) {
+
+    }
+
+    @Override
+    public void onSubscribe(Uri conditionId) {
+        Log.d(TAG, "subscribed to " + conditionId);
+        mSubscriptions.add(conditionId);
+    }
+
+    @Override
+    public void onUnsubscribe(Uri conditionId) {
+        Log.d(TAG, "unsubscribed from " + conditionId);
+        mSubscriptions.remove(conditionId);
+    }
+
+    public abstract static class BooleanResultCatcher extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            accept(getResultExtras(true).getBoolean(EXTRA_BOOLEAN, false));
+        }
+
+        abstract public void accept(boolean result);
+    }
+
+    private static void requestConnected(Context context, String action,
+            BooleanResultCatcher catcher) {
+        Intent broadcast = new Intent(action);
+        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+    }
+
+    public abstract static class ParcelableListResultCatcher extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            accept(getResultExtras(true).getParcelableArrayList(EXTRA_PAYLOAD));
+        }
+
+        abstract public void accept(List<Parcelable> result);
+    }
+
+    private static void requestParcelableListResult(Context context, String action,
+            ParcelableListResultCatcher 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/sample/SampleTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sample/SampleTestActivity.java
index 41bc303..678aeca 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sample/SampleTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sample/SampleTestActivity.java
@@ -77,14 +77,15 @@
         double[] metricValues = new double[] {1, 11, 21, 1211, 111221};
 
         // Record metric results
-        getReportLog().setSummary(
-                "Sample Summary", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
-        getReportLog().addValues("Sample Values", metricValues, ResultType.NEUTRAL, ResultUnit.FPS);
+        getReportLog().setSummary("Sample Summary", 1.0, ResultType.HIGHER_BETTER,
+                ResultUnit.BYTE);
+        getReportLog().addValues("Sample Values", metricValues, ResultType.NEUTRAL,
+                ResultUnit.FPS);
 
         // Alternatively, activities can invoke TestResult directly to record metrics
         ReportLog reportLog = new PassFailButtons.CtsVerifierReportLog();
         reportLog.setSummary("Sample Summary", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
-        getReportLog().addValues("Sample Values", metricValues, ResultType.NEUTRAL, ResultUnit.FPS);
+        reportLog.addValues("Sample Values", metricValues, ResultType.NEUTRAL, ResultUnit.FPS);
         TestResult.setPassedResult(this, "manualSample", "manualDetails", reportLog);
     }
 
diff --git a/build/compatibility_test_suite.mk b/build/compatibility_test_suite.mk
new file mode 100644
index 0000000..6430efa
--- /dev/null
+++ b/build/compatibility_test_suite.mk
@@ -0,0 +1,51 @@
+# Copyright (C) 2015 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.
+
+#
+# Builds a compatibility test suite.
+#
+
+# Generate the SuiteInfo.java
+suite_info_java := $(call intermediates-dir-for,JAVA_LIBRARIES,$(LOCAL_MODULE),true,COMMON)/com/android/compatibility/SuiteInfo.java
+$(suite_info_java): PRIVATE_SUITE_BUILD_NUMBER := $(LOCAL_SUITE_BUILD_NUMBER)
+$(suite_info_java): PRIVATE_SUITE_NAME := $(LOCAL_SUITE_NAME)
+$(suite_info_java): PRIVATE_SUITE_FULLNAME := $(LOCAL_SUITE_FULLNAME)
+$(suite_info_java): PRIVATE_SUITE_VERSION := $(LOCAL_SUITE_VERSION)
+$(suite_info_java): cts/build/compatibility_test_suite.mk $(LOCAL_MODULE_MAKEFILE)
+	@echo Generating: $@
+	$(hide) mkdir -p $(dir $@)
+	$(hide) echo "/* This file is auto generated by Android.mk.  Do not modify. */" > $@
+	$(hide) echo "package com.android.compatibility;" >> $@
+	$(hide) echo "public class SuiteInfo {" >> $@
+	$(hide) echo "    public static final String BUILD_NUMBER = \"$(PRIVATE_SUITE_BUILD_NUMBER)\";" >> $@
+	$(hide) echo "    public static final String NAME = \"$(PRIVATE_SUITE_NAME)\";" >> $@
+	$(hide) echo "    public static final String FULLNAME = \"$(PRIVATE_SUITE_FULLNAME)\";" >> $@
+	$(hide) echo "    public static final String VERSION = \"$(PRIVATE_SUITE_VERSION)\";" >> $@
+	$(hide) echo "}" >> $@
+
+# Reset variables
+LOCAL_SUITE_BUILD_NUMBER :=
+LOCAL_SUITE_NAME :=
+LOCAL_SUITE_FULLNAME :=
+LOCAL_SUITE_VERSION :=
+
+# Include the SuiteInfo.java
+LOCAL_GENERATED_SOURCES := $(suite_info_java)
+
+# Add the base libraries
+LOCAL_JAVA_LIBRARIES += tradefed-prebuilt hosttestlib compatibility-host-util
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/build/config.mk b/build/config.mk
index 56d4ae6..eae7c00 100644
--- a/build/config.mk
+++ b/build/config.mk
@@ -16,6 +16,8 @@
 # directory before creating the final CTS distribution.
 CTS_TESTCASES_OUT := $(HOST_OUT)/cts/android-cts/repository/testcases
 
+COMPATIBILITY_TESTCASES_OUT_cts_v2 := $(HOST_OUT)/cts_v2/android-cts_v2/testcases
+
 # Scanners of source files for tests which are then inputed into
 # the XML generator to produce test XMLs.
 CTS_NATIVE_TEST_SCANNER := $(HOST_OUT_EXECUTABLES)/cts-native-scanner
@@ -38,6 +40,7 @@
 CTS_MODULE_TEST_CONFIG := AndroidTest.xml
 
 # CTS build rules
+BUILD_COMPATIBILITY_SUITE := cts/build/compatibility_test_suite.mk
 BUILD_CTS_EXECUTABLE := cts/build/test_executable.mk
 BUILD_CTS_PACKAGE := cts/build/test_package.mk
 BUILD_CTS_GTEST_PACKAGE := cts/build/test_gtest_package.mk
diff --git a/build/device_info_package.mk b/build/device_info_package.mk
index 0aaa8aa..036218a 100644
--- a/build/device_info_package.mk
+++ b/build/device_info_package.mk
@@ -17,9 +17,32 @@
 #
 
 DEVICE_INFO_PACKAGE := com.android.compatibility.common.deviceinfo
-DEVICE_INFO_INSTRUMENT := com.android.compatibility.common.deviceinfo.DeviceInfoInstrument
+DEVICE_INFO_INSTRUMENT := android.support.test.runner.AndroidJUnitRunner
 DEVICE_INFO_PERMISSIONS += android.permission.WRITE_EXTERNAL_STORAGE
-DEVICE_INFO_ACTIVITIES += $(DEVICE_INFO_PACKAGE).GenericDeviceInfo $(DEVICE_INFO_PACKAGE).PackageDeviceInfo
+DEVICE_INFO_ACTIVITIES += \
+  $(DEVICE_INFO_PACKAGE).CameraDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).ConfigurationDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).CpuDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).FeatureDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).GenericDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).GraphicsDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).LibraryDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).LocaleDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).MediaDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).MemoryDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).PackageDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).PropertyDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).ScreenDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).StorageDeviceInfo \
+  $(DEVICE_INFO_PACKAGE).UserDeviceInfo
+
+ifeq ($(DEVICE_INFO_MIN_SDK),)
+DEVICE_INFO_MIN_SDK := 8
+endif
+
+ifeq ($(DEVICE_INFO_TARGET_SDK),)
+DEVICE_INFO_TARGET_SDK := 8
+endif
 
 # Add the base device info
 LOCAL_STATIC_JAVA_LIBRARIES += compatibility-device-info
@@ -34,6 +57,8 @@
 $(manifest_xml): PRIVATE_INFO_ACTIVITIES := $(foreach activity,$(DEVICE_INFO_ACTIVITIES),-a $(activity))
 $(manifest_xml): PRIVATE_PACKAGE := $(DEVICE_INFO_PACKAGE)
 $(manifest_xml): PRIVATE_INSTRUMENT := $(DEVICE_INFO_INSTRUMENT)
+$(manifest_xml): PRIVATE_MIN_SDK := $(DEVICE_INFO_MIN_SDK)
+$(manifest_xml): PRIVATE_TARGET_SDK := $(DEVICE_INFO_TARGET_SDK)
 
 # Regenerate manifest.xml if the generator jar, */cts-device-info/Android.mk, or this file is changed.
 $(manifest_xml): $(MANIFEST_GENERATOR_JAR) $(LOCAL_PATH)/Android.mk cts/build/device_info_package.mk
@@ -44,9 +69,13 @@
 						$(PRIVATE_INFO_ACTIVITIES) \
 						-p $(PRIVATE_PACKAGE) \
 						-i $(PRIVATE_INSTRUMENT) \
+						-s $(PRIVATE_MIN_SDK) \
+						-t $(PRIVATE_TARGET_SDK) \
 						-o $@
 
 # Reset variables
+DEVICE_INFO_MIN_SDK :=
+DEVICE_INFO_TARGET_SDK :=
 DEVICE_INFO_PACKAGE :=
 DEVICE_INFO_INSTRUMENT :=
 DEVICE_INFO_PERMISSIONS :=
diff --git a/build/module_test_config.mk b/build/module_test_config.mk
index 6584ef2..fec4893 100644
--- a/build/module_test_config.mk
+++ b/build/module_test_config.mk
@@ -12,10 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-cts_module_test_config := $(if $(wildcard \
-	$(LOCAL_PATH)/$(CTS_MODULE_TEST_CONFIG)), \
-	$(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).config)
-ifneq ($(cts_module_test_config),)
-$(cts_module_test_config): $(LOCAL_PATH)/$(CTS_MODULE_TEST_CONFIG) | $(ACP)
+ifneq ($(LOCAL_CTS_MODULE_CONFIG),)
+cts_module_test_config := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).config
+$(cts_module_test_config): $(LOCAL_CTS_MODULE_CONFIG) | $(ACP)
 	$(call copy-file-to-target)
 endif
+# clear var
+LOCAL_CTS_MODULE_CONFIG :=
diff --git a/build/test_deqp_package.mk b/build/test_deqp_package.mk
index 570669d..f98f342 100644
--- a/build/test_deqp_package.mk
+++ b/build/test_deqp_package.mk
@@ -18,13 +18,13 @@
 
 CTS_DEQP_CONFIG_PATH := $(call my-dir)
 
-cts_library_xmls:=$(foreach xml_file, $(call find-files-in-subdirs, external/deqp/android/cts/master, 'com.drawelements.deqp.$(DEQP_API).*xml', .), $(CTS_TESTCASES_OUT)/$(xml_file))
-$(cts_library_xmls) : PRIVATE_API := $(DEQP_API)
-$(cts_library_xmls) : PRIVATE_TEST_NAME := $(DEQP_TEST_NAME)
-$(cts_library_xmls) : PRIVATE_TEST_PACKAGE := com.drawelements.deqp.$(DEQP_API)
-$(cts_library_xmls) : PRIVATE_DUMMY_CASELIST := $(CTS_DEQP_CONFIG_PATH)/deqp_dummy_test_list
-$(cts_library_xmls) : $(CTS_TESTCASES_OUT)/%.xml: external/deqp/android/cts/master/%.xml $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
-	$(hide) echo Generating test description $@
+cts_library_xml := $(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(DEQP_API).xml
+$(cts_library_xml): MUSTPASS_XML_FILE := external/deqp/android/cts/master/com.drawelements.deqp.$(DEQP_API).xml
+$(cts_library_xml): PRIVATE_TEST_NAME := $(DEQP_TEST_NAME)
+$(cts_library_xml): PRIVATE_TEST_PACKAGE := com.drawelements.deqp.$(DEQP_API)
+$(cts_library_xml): PRIVATE_DUMMY_CASELIST := $(CTS_DEQP_CONFIG_PATH)/deqp_dummy_test_list
+$(cts_library_xml): external/deqp/android/cts/master/com.drawelements.deqp.$(DEQP_API).xml external/deqp/android/cts/mnc/$(DEQP_API)-master.txt $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
+	$(hide) echo Generating test description for $(PRIVATE_TEST_NAME)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
 
 # Query build ABIs by routing a dummy test list through xml generator and parse result. Use sed to insert the ABI string into the XML files.
@@ -37,5 +37,5 @@
 									< $(PRIVATE_DUMMY_CASELIST) \
 									| grep --only-matching -e " abis=\"[^\"]*\""` && \
 			$(SED_EXTENDED) -e "s:^(\s*)<Test ((.[^/]|[^/])*)(/?)>$$:\1<Test \2 $${SUPPORTED_ABI_ATTR}\4>:" \
-				< $< \
+				< $(MUSTPASS_XML_FILE) \
 				> $@
diff --git a/build/test_host_java_library.mk b/build/test_host_java_library.mk
index b4c7e63..7fdefb5 100644
--- a/build/test_host_java_library.mk
+++ b/build/test_host_java_library.mk
@@ -29,11 +29,6 @@
 cts_src_dirs := $(addprefix -s , $(cts_src_dirs))
 
 cts_library_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml
-ifeq ($(cts_runtime_hint),)
-$(cts_library_xml): PRIVATE_CTS_RUNTIME_HINT := "0"
-else
-$(cts_library_xml): PRIVATE_CTS_RUNTIME_HINT := $(cts_runtime_hint)
-endif
 $(cts_library_xml): PRIVATE_SRC_DIRS := $(cts_src_dirs)
 $(cts_library_xml): PRIVATE_TEST_PACKAGE := $(LOCAL_CTS_TEST_PACKAGE)
 $(cts_library_xml): PRIVATE_LIBRARY := $(LOCAL_MODULE)
@@ -49,7 +44,6 @@
 						-j $(PRIVATE_JAR_PATH) \
 						-n $(PRIVATE_LIBRARY) \
 						-p $(PRIVATE_TEST_PACKAGE) \
-						-x "runtimeHint->$(PRIVATE_CTS_RUNTIME_HINT)" \
 						-e $(CTS_EXPECTATIONS) \
 						-b $(CTS_UNSUPPORTED_ABIS) \
 						-a $(CTS_TARGET_ARCH) \
diff --git a/build/test_package.mk b/build/test_package.mk
index 13e582e..c6b0865 100644
--- a/build/test_package.mk
+++ b/build/test_package.mk
@@ -39,11 +39,6 @@
 else
 PRIVATE_CTS_TEST_PACKAGE_NAME_ := android.$(notdir $(LOCAL_PATH))
 endif
-ifeq ($(cts_runtime_hint),)
-$(cts_package_xml): PRIVATE_CTS_RUNTIME_HINT := "0"
-else
-$(cts_package_xml): PRIVATE_CTS_RUNTIME_HINT := $(cts_runtime_hint)
-endif
 $(cts_package_xml): PRIVATE_TEST_PACKAGE := $(PRIVATE_CTS_TEST_PACKAGE_NAME_)
 $(cts_package_xml): PRIVATE_MANIFEST := $(LOCAL_PATH)/AndroidManifest.xml
 $(cts_package_xml): PRIVATE_TEST_TYPE := $(if $(LOCAL_CTS_TEST_RUNNER),$(LOCAL_CTS_TEST_RUNNER),'')
@@ -61,13 +56,9 @@
 						-i "$(PRIVATE_INSTRUMENTATION)" \
 						-n $(PRIVATE_PACKAGE) \
 						-p $(PRIVATE_TEST_PACKAGE) \
-						-x "runtimeHint->$(PRIVATE_CTS_RUNTIME_HINT)" \
 						-e $(CTS_EXPECTATIONS) \
 						-b $(CTS_UNSUPPORTED_ABIS) \
 						-a $(CTS_TARGET_ARCH) \
 						-o $@
 # Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
 $(my_register_name) : $(cts_package_xml) $(cts_module_test_config)
-
-# Make sure we clear cts_runtime_hint, so other parents will use the default if they do not set cts_runtime_hint.
-cts_runtime_hint :=
diff --git a/common/device-side/device-info/Android.mk b/common/device-side/device-info/Android.mk
index 0f5e8d3..927101b 100644
--- a/common/device-side/device-info/Android.mk
+++ b/common/device-side/device-info/Android.mk
@@ -25,6 +25,8 @@
 # uncomment when b/13282254 is fixed
 #LOCAL_SDK_VERSION := current
 
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java
new file mode 100644
index 0000000..4e379dc
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.media.CamcorderProfile;
+
+/**
+ * Camera information collector.
+ */
+public final class CameraDeviceInfo extends DeviceInfo {
+
+    @Override
+    protected void collectDeviceInfo() {
+        addResult("profile_480p", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P));
+        addResult("profile_720p", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P));
+        addResult("profile_1080p", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P));
+        addResult("profile_cif", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_CIF));
+        addResult("profile_qcif", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QCIF));
+        addResult("profile_qvga", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QVGA));
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ConfigurationDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ConfigurationDeviceInfo.java
new file mode 100644
index 0000000..4ce905e
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ConfigurationDeviceInfo.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.content.res.Configuration;
+
+/**
+ * Configuration device info collector.
+ */
+public final class ConfigurationDeviceInfo extends DeviceInfo {
+
+    @Override
+    protected void collectDeviceInfo() {
+        Configuration con = getInstrumentation().getContext().getResources().getConfiguration();
+        addResult("touchscreen", con.touchscreen);
+        addResult("navigation", con.navigation);
+        addResult("keyboard", con.keyboard);
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CpuDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CpuDeviceInfo.java
new file mode 100644
index 0000000..45d8e47
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CpuDeviceInfo.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+/**
+ * CPU device info collector.
+ */
+public final class CpuDeviceInfo extends DeviceInfo {
+
+    @Override
+    protected void collectDeviceInfo() {
+        addResult("available_processors", Runtime.getRuntime().availableProcessors());
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfo.java
new file mode 100644
index 0000000..151e89a
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfo.java
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Environment;
+import android.test.InstrumentationTestCase;
+import android.text.TextUtils;
+import android.util.JsonWriter;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Collect device information on target device and write to a JSON file.
+ */
+public abstract class DeviceInfo extends InstrumentationTestCase {
+
+    private enum ResultCode {
+        // Collection started.
+        STARTED,
+        // Collection completed.
+        COMPLETED,
+        // Collection completed with error.
+        ERROR,
+        // Collection failed to complete.
+        FAILED
+    }
+
+    private static final int MAX_STRING_VALUE_LENGTH = 1000;
+    private static final int MAX_ARRAY_LENGTH = 1000;
+
+    private static final String LOG_TAG = "ExtendedDeviceInfo";
+
+    private JsonWriter mJsonWriter = null;
+    private String mResultFilePath = null;
+    private String mErrorMessage = null;
+    private ResultCode mResultCode = ResultCode.STARTED;
+
+    Set<String> mActivityList = new HashSet<String>();
+
+    public void testCollectDeviceInfo() {
+        if (!mActivityList.contains(getClass().getName())) {
+            return;
+        }
+
+        if (createFilePath()) {
+            createJsonWriter();
+            startJsonWriter();
+            try {
+                collectDeviceInfo();
+            } catch(Exception | Error e) {
+                error(e.getMessage());
+            }
+            closeJsonWriter();
+
+            if (mResultCode == ResultCode.STARTED) {
+                mResultCode = ResultCode.COMPLETED;
+            }
+        }
+
+        sendStatus();
+
+        String message = getClass().getSimpleName() + " collection completed.";
+        assertEquals(message, ResultCode.COMPLETED, mResultCode);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Build the list of supported activities that can run collection.
+        ActivityInfo[] activities = null;
+        try {
+            activities = getContext().getPackageManager().getPackageInfo(
+                getContext().getPackageName(), PackageManager.GET_ACTIVITIES).activities;
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "Exception occurred while getting activities.", e);
+            return;
+        }
+
+        for (ActivityInfo activityInfo : activities) {
+            mActivityList.add(activityInfo.name);
+        }
+    }
+
+    /**
+     * Method to collect device information.
+     */
+    protected abstract void collectDeviceInfo();
+
+    protected Context getContext() {
+        return getInstrumentation().getContext();
+    }
+
+    /**
+     * Sends status to instrumentation.
+     */
+    void sendStatus() {
+        Bundle bundle = new Bundle();
+        String className = getClass().getSimpleName();
+        if (this instanceof GenericDeviceInfo) {
+            ((GenericDeviceInfo) this).putDeviceInfo(bundle);
+        }
+        if (!TextUtils.isEmpty(mErrorMessage)) {
+            bundle.putString("DEVICE_INFO_ERROR_" + className, mErrorMessage);
+        }
+        if (mResultCode == ResultCode.COMPLETED) {
+            bundle.putString("DEVICE_INFO_FILE_" + className, mResultFilePath);
+        }
+        getInstrumentation().sendStatus(Activity.RESULT_OK, bundle);
+    }
+
+    /**
+     * Returns the path to the json file if collector completed successfully.
+     */
+    String getResultFilePath() {
+        return mResultFilePath;
+    }
+
+    private void error(String message) {
+        mResultCode = ResultCode.ERROR;
+        mErrorMessage = message;
+        Log.e(LOG_TAG, message);
+    }
+
+    private void failed(String message) {
+        mResultCode = ResultCode.FAILED;
+        mErrorMessage = message;
+        Log.e(LOG_TAG, message);
+    }
+
+    private boolean createFilePath() {
+        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+            failed("External storage is not mounted");
+            return false;
+        }
+        final File dir = new File(Environment.getExternalStorageDirectory(), "device-info-files");
+        if (!dir.mkdirs() && !dir.isDirectory()) {
+            failed("Cannot create directory for device info files");
+            return false;
+        }
+
+        // Create file at /sdcard/device-info-files/<class_name>.deviceinfo.json
+        final File jsonFile = new File(dir, getClass().getSimpleName() + ".deviceinfo.json");
+        try {
+            jsonFile.createNewFile();
+        } catch (Exception e) {
+            failed("Cannot create file to collect device info");
+            return false;
+        }
+        mResultFilePath = jsonFile.getAbsolutePath();
+        return true;
+    }
+
+    private void createJsonWriter() {
+        try {
+            FileOutputStream out = new FileOutputStream(mResultFilePath);
+            mJsonWriter = new JsonWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
+            // TODO(agathaman): remove to make json output less pretty
+            mJsonWriter.setIndent("  ");
+        } catch (Exception e) {
+            failed("Failed to create JSON writer: " + e.getMessage());
+        }
+    }
+
+    private void startJsonWriter() {
+        try {
+            mJsonWriter.beginObject();
+        } catch (Exception e) {
+            failed("Failed to begin JSON object: " + e.getMessage());
+        }
+    }
+
+    private void closeJsonWriter() {
+        try {
+            mJsonWriter.endObject();
+            mJsonWriter.close();
+        } catch (Exception e) {
+            failed("Failed to close JSON object: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Start a new group of result.
+     */
+    public void startGroup() {
+        try {
+            mJsonWriter.beginObject();
+        } catch (Exception e) {
+            error("Failed to begin JSON group: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Start a new group of result with specified name.
+     */
+    public void startGroup(String name) {
+        try {
+            mJsonWriter.name(name);
+            mJsonWriter.beginObject();
+        } catch (Exception e) {
+            error("Failed to begin JSON group: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Complete adding result to the last started group.
+     */
+    public void endGroup() {
+        try {
+            mJsonWriter.endObject();
+        } catch (Exception e) {
+            error("Failed to end JSON group: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Start a new array of result.
+     */
+    public void startArray() {
+        try {
+            mJsonWriter.beginArray();
+        } catch (Exception e) {
+            error("Failed to begin JSON array: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Start a new array of result with specified name.
+     */
+    public void startArray(String name) {
+        checkName(name);
+        try {
+            mJsonWriter.name(name);
+            mJsonWriter.beginArray();
+        } catch (Exception e) {
+            error("Failed to begin JSON array: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Complete adding result to the last started array.
+     */
+    public void endArray() {
+        try {
+            mJsonWriter.endArray();
+        } catch (Exception e) {
+            error("Failed to end JSON group: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Add a double value result.
+     */
+    public void addResult(String name, double value) {
+        checkName(name);
+        try {
+            mJsonWriter.name(name).value(value);
+        } catch (Exception e) {
+            error("Failed to add result for type double: " + e.getMessage());
+        }
+    }
+
+    /**
+    * Add a long value result.
+    */
+    public void addResult(String name, long value) {
+        checkName(name);
+        try {
+            mJsonWriter.name(name).value(value);
+        } catch (Exception e) {
+            error("Failed to add result for type long: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Add an int value result.
+     */
+    public void addResult(String name, int value) {
+        checkName(name);
+        try {
+            mJsonWriter.name(name).value((Number) value);
+        } catch (Exception e) {
+            error("Failed to add result for type int: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Add a boolean value result.
+     */
+    public void addResult(String name, boolean value) {
+        checkName(name);
+        try {
+            mJsonWriter.name(name).value(value);
+        } catch (Exception e) {
+            error("Failed to add result for type boolean: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Add a String value result.
+     */
+    public void addResult(String name, String value) {
+        checkName(name);
+        try {
+            mJsonWriter.name(name).value(checkString(value));
+        } catch (Exception e) {
+            error("Failed to add result for type String: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Add a double array result.
+     */
+    public void addArray(String name, double[] list) {
+        checkName(name);
+        try {
+            mJsonWriter.name(name);
+            mJsonWriter.beginArray();
+            for (double value : checkArray(list)) {
+                mJsonWriter.value(value);
+            }
+            mJsonWriter.endArray();
+        } catch (Exception e) {
+            error("Failed to add result array for type double: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Add a long array result.
+     */
+    public void addArray(String name, long[] list) {
+        checkName(name);
+        try {
+        mJsonWriter.name(name);
+        mJsonWriter.beginArray();
+        for (long value : checkArray(list)) {
+            mJsonWriter.value(value);
+        }
+            mJsonWriter.endArray();
+        } catch (Exception e) {
+            error("Failed to add result array for type long: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Add an int array result.
+     */
+    public void addArray(String name, int[] list) {
+        checkName(name);
+        try {
+            mJsonWriter.name(name);
+            mJsonWriter.beginArray();
+            for (int value : checkArray(list)) {
+                mJsonWriter.value((Number) value);
+            }
+            mJsonWriter.endArray();
+        } catch (Exception e) {
+            error("Failed to add result array for type int: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Add a boolean array result.
+     */
+    public void addArray(String name, boolean[] list) {
+        checkName(name);
+        try {
+            mJsonWriter.name(name);
+            mJsonWriter.beginArray();
+            for (boolean value : checkArray(list)) {
+                mJsonWriter.value(value);
+            }
+            mJsonWriter.endArray();
+        } catch (Exception e) {
+            error("Failed to add result array for type boolean: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Add a String array result.
+     */
+    public void addArray(String name, String[] list) {
+        checkName(name);
+        try {
+            mJsonWriter.name(name);
+            mJsonWriter.beginArray();
+            for (String value : checkArray(list)) {
+                mJsonWriter.value(checkString(value));
+            }
+            mJsonWriter.endArray();
+        } catch (Exception e) {
+            error("Failed to add result array for type Sting: " + e.getMessage());
+        }
+    }
+
+    private static boolean[] checkArray(boolean[] values) {
+        if (values.length > MAX_ARRAY_LENGTH) {
+            return Arrays.copyOf(values, MAX_ARRAY_LENGTH);
+        } else {
+            return values;
+        }
+    }
+
+    private static double[] checkArray(double[] values) {
+        if (values.length > MAX_ARRAY_LENGTH) {
+            return Arrays.copyOf(values, MAX_ARRAY_LENGTH);
+        } else {
+            return values;
+        }
+    }
+
+    private static int[] checkArray(int[] values) {
+        if (values.length > MAX_ARRAY_LENGTH) {
+            return Arrays.copyOf(values, MAX_ARRAY_LENGTH);
+        } else {
+            return values;
+        }
+    }
+
+    private static long[] checkArray(long[] values) {
+        if (values.length > MAX_ARRAY_LENGTH) {
+            return Arrays.copyOf(values, MAX_ARRAY_LENGTH);
+        } else {
+            return values;
+        }
+    }
+
+    private static String[] checkArray(String[] values) {
+        if (values.length > MAX_ARRAY_LENGTH) {
+            return Arrays.copyOf(values, MAX_ARRAY_LENGTH);
+        } else {
+            return values;
+        }
+    }
+
+    private static String checkString(String value) {
+        if (value.length() > MAX_STRING_VALUE_LENGTH) {
+            return value.substring(0, MAX_STRING_VALUE_LENGTH);
+        }
+        return value;
+    }
+
+    private static String checkName(String value) {
+        if (TextUtils.isEmpty(value)) {
+            throw new NullPointerException();
+        }
+        return value;
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoActivity.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoActivity.java
deleted file mode 100644
index f9de6eb..0000000
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoActivity.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.deviceinfo;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Environment;
-import android.text.TextUtils;
-import android.util.JsonWriter;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-
-/**
- * Collect device information on target device and write to a JSON file.
- */
-public abstract class DeviceInfoActivity extends Activity {
-
-    /** Device info result code: collector failed to complete. */
-    private static final int DEVICE_INFO_RESULT_FAILED = -2;
-    /** Device info result code: collector completed with error. */
-    private static final int DEVICE_INFO_RESULT_ERROR = -1;
-    /** Device info result code: collector has started but not completed. */
-    private static final int DEVICE_INFO_RESULT_STARTED = 0;
-    /** Device info result code: collector completed success. */
-    private static final int DEVICE_INFO_RESULT_OK = 1;
-
-    private static final int MAX_STRING_VALUE_LENGTH = 1000;
-    private static final int MAX_ARRAY_LENGTH = 1000;
-
-    private static final String LOG_TAG = "DeviceInfoActivity";
-
-    private CountDownLatch mDone = new CountDownLatch(1);
-    private JsonWriter mJsonWriter = null;
-    private String mResultFilePath = null;
-    private String mErrorMessage = "Collector has started.";
-    private int mResultCode = DEVICE_INFO_RESULT_STARTED;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        if (createFilePath()) {
-            createJsonWriter();
-            startJsonWriter();
-            collectDeviceInfo();
-            closeJsonWriter();
-
-            if (mResultCode == DEVICE_INFO_RESULT_STARTED) {
-                mResultCode = DEVICE_INFO_RESULT_OK;
-            }
-        }
-
-        Intent data = new Intent();
-        if (mResultCode == DEVICE_INFO_RESULT_OK) {
-            data.setData(Uri.parse(mResultFilePath));
-            setResult(RESULT_OK, data);
-        } else {
-            data.setData(Uri.parse(mErrorMessage));
-            setResult(RESULT_CANCELED, data);
-        }
-
-        mDone.countDown();
-        finish();
-    }
-
-    /**
-     * Method to collect device information.
-     */
-    protected abstract void collectDeviceInfo();
-
-    void waitForActivityToFinish() {
-        try {
-            mDone.await();
-        } catch (Exception e) {
-            failed("Exception while waiting for activity to finish: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Returns the error message if collector did not complete successfully.
-     */
-    String getErrorMessage() {
-        if (mResultCode == DEVICE_INFO_RESULT_OK) {
-            return null;
-        }
-        return mErrorMessage;
-    }
-
-    /**
-     * Returns the path to the json file if collector completed successfully.
-     */
-    String getResultFilePath() {
-        if (mResultCode == DEVICE_INFO_RESULT_OK) {
-            return mResultFilePath;
-        }
-        return null;
-    }
-
-    private void error(String message) {
-        mResultCode = DEVICE_INFO_RESULT_ERROR;
-        mErrorMessage = message;
-        Log.e(LOG_TAG, message);
-    }
-
-    private void failed(String message) {
-        mResultCode = DEVICE_INFO_RESULT_FAILED;
-        mErrorMessage = message;
-        Log.e(LOG_TAG, message);
-    }
-
-    private boolean createFilePath() {
-        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-            failed("External storage is not mounted");
-            return false;
-        }
-        final File dir = new File(Environment.getExternalStorageDirectory(), "device-info-files");
-        if (!dir.mkdirs() && !dir.isDirectory()) {
-            failed("Cannot create directory for device info files");
-            return false;
-        }
-
-        // Create file at /sdcard/device-info-files/<class_name>.deviceinfo.json
-        final File jsonFile = new File(dir, getClass().getSimpleName() + ".deviceinfo.json");
-        try {
-            jsonFile.createNewFile();
-        } catch (Exception e) {
-            failed("Cannot create file to collect device info");
-            return false;
-        }
-        mResultFilePath = jsonFile.getAbsolutePath();
-        return true;
-    }
-
-    private void createJsonWriter() {
-        try {
-            FileOutputStream out = new FileOutputStream(mResultFilePath);
-            mJsonWriter = new JsonWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
-            // TODO(agathaman): remove to make json output less pretty
-            mJsonWriter.setIndent("  ");
-        } catch (Exception e) {
-            failed("Failed to create JSON writer: " + e.getMessage());
-        }
-    }
-
-    private void startJsonWriter() {
-        try {
-            mJsonWriter.beginObject();
-        } catch (Exception e) {
-            failed("Failed to begin JSON object: " + e.getMessage());
-        }
-    }
-
-    private void closeJsonWriter() {
-        try {
-            mJsonWriter.endObject();
-            mJsonWriter.close();
-        } catch (Exception e) {
-            failed("Failed to close JSON object: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Start a new group of result.
-     */
-    public void startGroup() {
-        try {
-            mJsonWriter.beginObject();
-        } catch (Exception e) {
-            error("Failed to begin JSON group: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Start a new group of result with specified name.
-     */
-    public void startGroup(String name) {
-        try {
-            mJsonWriter.name(name);
-            mJsonWriter.beginObject();
-        } catch (Exception e) {
-            error("Failed to begin JSON group: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Complete adding result to the last started group.
-     */
-    public void endGroup() {
-        try {
-            mJsonWriter.endObject();
-        } catch (Exception e) {
-            error("Failed to end JSON group: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Start a new array of result.
-     */
-    public void startArray() {
-        try {
-            mJsonWriter.beginArray();
-        } catch (Exception e) {
-            error("Failed to begin JSON array: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Start a new array of result with specified name.
-     */
-    public void startArray(String name) {
-        checkName(name);
-        try {
-            mJsonWriter.name(name);
-            mJsonWriter.beginArray();
-        } catch (Exception e) {
-            error("Failed to begin JSON array: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Complete adding result to the last started array.
-     */
-    public void endArray() {
-        try {
-            mJsonWriter.endArray();
-        } catch (Exception e) {
-            error("Failed to end JSON group: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Add a double value result.
-     */
-    public void addResult(String name, double value) {
-        checkName(name);
-        try {
-            mJsonWriter.name(name).value(value);
-        } catch (Exception e) {
-            error("Failed to add result for type double: " + e.getMessage());
-        }
-    }
-
-    /**
-    * Add a long value result.
-    */
-    public void addResult(String name, long value) {
-        checkName(name);
-        try {
-            mJsonWriter.name(name).value(value);
-        } catch (Exception e) {
-            error("Failed to add result for type long: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Add an int value result.
-     */
-    public void addResult(String name, int value) {
-        checkName(name);
-        try {
-            mJsonWriter.name(name).value((Number) value);
-        } catch (Exception e) {
-            error("Failed to add result for type int: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Add a boolean value result.
-     */
-    public void addResult(String name, boolean value) {
-        checkName(name);
-        try {
-            mJsonWriter.name(name).value(value);
-        } catch (Exception e) {
-            error("Failed to add result for type boolean: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Add a String value result.
-     */
-    public void addResult(String name, String value) {
-        checkName(name);
-        try {
-            mJsonWriter.name(name).value(checkString(value));
-        } catch (Exception e) {
-            error("Failed to add result for type String: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Add a double array result.
-     */
-    public void addArray(String name, double[] list) {
-        checkName(name);
-        try {
-            mJsonWriter.name(name);
-            mJsonWriter.beginArray();
-            for (double value : checkArray(list)) {
-                mJsonWriter.value(value);
-            }
-            mJsonWriter.endArray();
-        } catch (Exception e) {
-            error("Failed to add result array for type double: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Add a long array result.
-     */
-    public void addArray(String name, long[] list) {
-        checkName(name);
-        try {
-        mJsonWriter.name(name);
-        mJsonWriter.beginArray();
-        for (long value : checkArray(list)) {
-            mJsonWriter.value(value);
-        }
-            mJsonWriter.endArray();
-        } catch (Exception e) {
-            error("Failed to add result array for type long: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Add an int array result.
-     */
-    public void addArray(String name, int[] list) {
-        checkName(name);
-        try {
-            mJsonWriter.name(name);
-            mJsonWriter.beginArray();
-            for (int value : checkArray(list)) {
-                mJsonWriter.value((Number) value);
-            }
-            mJsonWriter.endArray();
-        } catch (Exception e) {
-            error("Failed to add result array for type int: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Add a boolean array result.
-     */
-    public void addArray(String name, boolean[] list) {
-        checkName(name);
-        try {
-            mJsonWriter.name(name);
-            mJsonWriter.beginArray();
-            for (boolean value : checkArray(list)) {
-                mJsonWriter.value(value);
-            }
-            mJsonWriter.endArray();
-        } catch (Exception e) {
-            error("Failed to add result array for type boolean: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Add a String array result.
-     */
-    public void addArray(String name, String[] list) {
-        checkName(name);
-        try {
-            mJsonWriter.name(name);
-            mJsonWriter.beginArray();
-            for (String value : checkArray(list)) {
-                mJsonWriter.value(checkString(value));
-            }
-            mJsonWriter.endArray();
-        } catch (Exception e) {
-            error("Failed to add result array for type Sting: " + e.getMessage());
-        }
-    }
-
-    private static boolean[] checkArray(boolean[] values) {
-        if (values.length > MAX_ARRAY_LENGTH) {
-            return Arrays.copyOf(values, MAX_ARRAY_LENGTH);
-        } else {
-            return values;
-        }
-    }
-
-    private static double[] checkArray(double[] values) {
-        if (values.length > MAX_ARRAY_LENGTH) {
-            return Arrays.copyOf(values, MAX_ARRAY_LENGTH);
-        } else {
-            return values;
-        }
-    }
-
-    private static int[] checkArray(int[] values) {
-        if (values.length > MAX_ARRAY_LENGTH) {
-            return Arrays.copyOf(values, MAX_ARRAY_LENGTH);
-        } else {
-            return values;
-        }
-    }
-
-    private static long[] checkArray(long[] values) {
-        if (values.length > MAX_ARRAY_LENGTH) {
-            return Arrays.copyOf(values, MAX_ARRAY_LENGTH);
-        } else {
-            return values;
-        }
-    }
-
-    private static String[] checkArray(String[] values) {
-        if (values.length > MAX_ARRAY_LENGTH) {
-            return Arrays.copyOf(values, MAX_ARRAY_LENGTH);
-        } else {
-            return values;
-        }
-    }
-
-    private static String checkString(String value) {
-        if (value.length() > MAX_STRING_VALUE_LENGTH) {
-            return value.substring(0, MAX_STRING_VALUE_LENGTH);
-        }
-        return value;
-    }
-
-    private static String checkName(String value) {
-        if (TextUtils.isEmpty(value)) {
-            throw new NullPointerException();
-        }
-        return value;
-    }
-}
-
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java
deleted file mode 100644
index 2f80911..0000000
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.deviceinfo;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * An instrumentation that runs all activities that extends DeviceInfoActivity.
- */
-public class DeviceInfoInstrument extends Instrumentation {
-
-    private static final String LOG_TAG = "ExtendedDeviceInfo";
-    private static final String COLLECTOR = "collector";
-
-    // List of collectors to run. If null or empty, all collectors will run.
-    private Set<String> mCollectorSet = new HashSet<String>();
-
-    // Results sent to the caller when this istrumentation completes.
-    private Bundle mBundle = new Bundle();
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        if (savedInstanceState != null) {
-            String collectorList = savedInstanceState.getString(COLLECTOR);
-            if (!TextUtils.isEmpty(collectorList)) {
-                for (String collector : TextUtils.split(collectorList, ",")) {
-                  if (!TextUtils.isEmpty(collector)) {
-                    mCollectorSet.add(collector);
-                  }
-                }
-            }
-        }
-        start();
-    }
-
-    @Override
-    public void onStart() {
-        try {
-            Context context = getContext();
-            ActivityInfo[] activities = context.getPackageManager().getPackageInfo(
-                    context.getPackageName(), PackageManager.GET_ACTIVITIES).activities;
-            for (ActivityInfo activityInfo : activities) {
-                runActivity(activityInfo.name);
-            }
-        } catch (Exception e) {
-            Log.e(LOG_TAG, "Exception occurred while running activities.", e);
-            // Returns INSTRUMENTATION_CODE: 0
-            finish(Activity.RESULT_CANCELED, mBundle);
-        }
-        // Returns INSTRUMENTATION_CODE: -1
-        finish(Activity.RESULT_OK, mBundle);
-    }
-
-    /**
-     * Returns true if the activity meets the criteria to run; otherwise, false.
-     */
-    private boolean isActivityRunnable(Class activityClass) {
-        // Don't run the base DeviceInfoActivity class.
-        if (DeviceInfoActivity.class == activityClass) {
-            return false;
-        }
-        // Don't run anything that doesn't extends DeviceInfoActivity.
-        if (!DeviceInfoActivity.class.isAssignableFrom(activityClass)) {
-            return false;
-        }
-        // Only run activity if mCollectorSet is empty or contains it.
-        if (mCollectorSet != null && mCollectorSet.size() > 0) {
-            return mCollectorSet.contains(activityClass.getName());
-        }
-        // Run anything that makes it here.
-        return true;
-    }
-
-    /**
-     * Runs a device info activity and return the file path where the results are written to.
-     */
-    private void runActivity(String activityName) throws Exception {
-        Class activityClass = null;
-        try {
-            activityClass = Class.forName(activityName);
-        } catch (ClassNotFoundException e) {
-            return;
-        }
-
-        if (activityClass == null || !isActivityRunnable(activityClass)) {
-            return;
-        }
-
-        Intent intent = new Intent();
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.setClassName(this.getContext(), activityName);
-
-        DeviceInfoActivity activity = (DeviceInfoActivity) startActivitySync(intent);
-        waitForIdleSync();
-        activity.waitForActivityToFinish();
-
-        String className = activityClass.getSimpleName();
-        String errorMessage = activity.getErrorMessage();
-        if (TextUtils.isEmpty(errorMessage)) {
-            mBundle.putString(className, activity.getResultFilePath());
-        } else {
-            mBundle.putString(className, errorMessage);
-            throw new Exception(errorMessage);
-        }
-    }
-}
-
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/FeatureDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/FeatureDeviceInfo.java
new file mode 100644
index 0000000..dff2313
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/FeatureDeviceInfo.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Feature device info collector.
+ */
+public final class FeatureDeviceInfo extends DeviceInfo {
+
+    @Override
+    protected void collectDeviceInfo() {
+        PackageManager packageManager = getInstrumentation().getContext().getPackageManager();
+        startArray("feature");
+
+        Set<String> checkedFeatures = new HashSet<String>();
+        for (String featureName : getPackageManagerFeatures()) {
+            checkedFeatures.add(featureName);
+            boolean hasFeature = packageManager.hasSystemFeature(featureName);
+            addFeature(featureName, "sdk", hasFeature);
+        }
+
+        FeatureInfo[] featureInfos = packageManager.getSystemAvailableFeatures();
+        if (featureInfos != null) {
+            for (FeatureInfo featureInfo : featureInfos) {
+                if (featureInfo.name != null && !checkedFeatures.contains(featureInfo.name)) {
+                    addFeature(featureInfo.name, "other", true);
+                }
+            }
+        }
+
+        endArray();
+    }
+
+    /**
+     * Use reflection to get the features defined by the SDK. If there are features that do not fit
+     * the convention of starting with "FEATURE_" then they will still be shown under the
+     * "Other Features" section.
+     *
+     * @return list of feature names from sdk
+     */
+    private List<String> getPackageManagerFeatures() {
+        try {
+            List<String> features = new ArrayList<String>();
+            Field[] fields = PackageManager.class.getFields();
+            for (Field field : fields) {
+                if (field.getName().startsWith("FEATURE_")) {
+                    String feature = (String) field.get(null);
+                    features.add(feature);
+                }
+            }
+            return features;
+        } catch (IllegalAccessException illegalAccess) {
+            throw new RuntimeException(illegalAccess);
+        }
+    }
+
+    private void addFeature(String name, String type, boolean available) {
+        startGroup();
+        addResult("name", name);
+        addResult("type", type);
+        addResult("available", available);
+        endGroup();
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
index 7df3dae..467269e 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
@@ -15,13 +15,6 @@
  */
 package com.android.compatibility.common.deviceinfo;
 
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
@@ -29,29 +22,20 @@
 import android.os.UserManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Display;
-import android.view.WindowManager;
 
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Scanner;
-import java.util.Set;
+import java.lang.Integer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
 
-import com.android.compatibility.common.deviceinfo.DeviceInfoActivity;
+import com.android.compatibility.common.deviceinfo.DeviceInfo;
 
 /**
  * Generic device info collector.
  */
-public class GenericDeviceInfo extends DeviceInfoActivity {
+public class GenericDeviceInfo extends DeviceInfo {
 
+    public static final String DEVICE_INFO_GENERIC = "DEVICE_INFO_GENERIC_%s";
     public static final String BUILD_ID = "build_id";
     public static final String BUILD_PRODUCT = "build_product";
     public static final String BUILD_DEVICE = "build_device";
@@ -69,48 +53,58 @@
     public static final String BUILD_SERIAL = "build_serial";
     public static final String BUILD_VERSION_RELEASE = "build_version_release";
     public static final String BUILD_VERSION_SDK = "build_version_sdk";
+    public static final String BUILD_VERSION_SDK_INT = "build_version_sdk_int";
     public static final String BUILD_VERSION_BASE_OS = "build_version_base_os";
     public static final String BUILD_VERSION_SECURITY_PATCH = "build_version_security_patch";
 
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
+    private final Map<String, String> mDeviceInfo = new HashMap<>();
 
     @Override
     protected void collectDeviceInfo() {
-        addResult(BUILD_ID, Build.ID);
-        addResult(BUILD_PRODUCT, Build.PRODUCT);
-        addResult(BUILD_DEVICE, Build.DEVICE);
-        addResult(BUILD_BOARD, Build.BOARD);
-        addResult(BUILD_MANUFACTURER, Build.MANUFACTURER);
-        addResult(BUILD_BRAND, Build.BRAND);
-        addResult(BUILD_MODEL, Build.MODEL);
-        addResult(BUILD_TYPE, Build.TYPE);
-        addResult(BUILD_FINGERPRINT, Build.FINGERPRINT);
-        addResult(BUILD_ABI, Build.CPU_ABI);
-        addResult(BUILD_ABI2, Build.CPU_ABI2);
-        addResult(BUILD_SERIAL, Build.SERIAL);
-        addResult(BUILD_VERSION_RELEASE, Build.VERSION.RELEASE);
-        addResult(BUILD_VERSION_SDK, Build.VERSION.SDK);
+        addDeviceInfo(BUILD_ID, Build.ID);
+        addDeviceInfo(BUILD_PRODUCT, Build.PRODUCT);
+        addDeviceInfo(BUILD_DEVICE, Build.DEVICE);
+        addDeviceInfo(BUILD_BOARD, Build.BOARD);
+        addDeviceInfo(BUILD_MANUFACTURER, Build.MANUFACTURER);
+        addDeviceInfo(BUILD_BRAND, Build.BRAND);
+        addDeviceInfo(BUILD_MODEL, Build.MODEL);
+        addDeviceInfo(BUILD_TYPE, Build.TYPE);
+        addDeviceInfo(BUILD_FINGERPRINT, Build.FINGERPRINT);
+        addDeviceInfo(BUILD_ABI, Build.CPU_ABI);
+        addDeviceInfo(BUILD_ABI2, Build.CPU_ABI2);
+        addDeviceInfo(BUILD_SERIAL, Build.SERIAL);
+        addDeviceInfo(BUILD_VERSION_RELEASE, Build.VERSION.RELEASE);
+        addDeviceInfo(BUILD_VERSION_SDK, Build.VERSION.SDK);
+        addDeviceInfo(BUILD_VERSION_SDK_INT, Integer.toString(Build.VERSION.SDK_INT));
 
-         // Collect build fields available in API level 21
+        // Collect build fields available in API level 21
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            addResult(BUILD_ABIS, TextUtils.join(",", Build.SUPPORTED_ABIS));
-            addResult(BUILD_ABIS_32, TextUtils.join(",", Build.SUPPORTED_32_BIT_ABIS));
-            addResult(BUILD_ABIS_64, TextUtils.join(",", Build.SUPPORTED_64_BIT_ABIS));
+            addDeviceInfo(BUILD_ABIS, TextUtils.join(",", Build.SUPPORTED_ABIS));
+            addDeviceInfo(BUILD_ABIS_32, TextUtils.join(",", Build.SUPPORTED_32_BIT_ABIS));
+            addDeviceInfo(BUILD_ABIS_64, TextUtils.join(",", Build.SUPPORTED_64_BIT_ABIS));
         }
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            addResult(BUILD_VERSION_BASE_OS, Build.VERSION.BASE_OS);
-            addResult(BUILD_VERSION_SECURITY_PATCH, Build.VERSION.SECURITY_PATCH);
+            addDeviceInfo(BUILD_VERSION_BASE_OS, Build.VERSION.BASE_OS);
+            addDeviceInfo(BUILD_VERSION_SECURITY_PATCH, Build.VERSION.SECURITY_PATCH);
         } else {
             // Access system properties directly because Build.Version.BASE_OS and
             // Build.Version.SECURITY_PATCH are not defined pre-M.
-            addResult(BUILD_VERSION_BASE_OS,
+            addDeviceInfo(BUILD_VERSION_BASE_OS,
                     SystemProperties.get("ro.build.version.base_os", ""));
-            addResult(BUILD_VERSION_SECURITY_PATCH,
+            addDeviceInfo(BUILD_VERSION_SECURITY_PATCH,
                     SystemProperties.get("ro.build.version.security_patch", ""));
         }
     }
+
+    private void addDeviceInfo(String key, String value) {
+        mDeviceInfo.put(key, value);
+        addResult(key, value);
+    }
+
+    protected void putDeviceInfo(Bundle bundle) {
+        for (Entry<String, String> entry : mDeviceInfo.entrySet()) {
+            bundle.putString(String.format(DEVICE_INFO_GENERIC, entry.getKey()), entry.getValue());
+        }
+    }
 }
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GlesStubActivity.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GlesStubActivity.java
new file mode 100644
index 0000000..1f93aaa
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GlesStubActivity.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.view.Window;
+import android.view.WindowManager;
+import android.opengl.GLES20;
+import android.opengl.GLES30;
+import android.opengl.GLSurfaceView;
+import android.util.Log;
+
+import java.util.Locale;
+import java.util.HashSet;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/** Stub activity to collect data from the GlesView */
+public final class GlesStubActivity extends Activity {
+
+    private static final String LOG_TAG = "GlesStubActivity";
+    private int mVersion = -1;
+    private GraphicsDeviceInfo mGraphicsDeviceInfo;
+    private CountDownLatch mDone = new CountDownLatch(1);
+    private HashSet<String> mOpenGlExtensions = new HashSet<String>();
+    private HashSet<String> mFormats = new HashSet<String>();
+    private String mGraphicsVendor;
+    private String mGraphicsRenderer;
+
+    @Override
+    public void onCreate(Bundle bundle) {
+        // Dismiss keyguard and keep screen on while this test is on.
+        Window window = getWindow();
+        window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
+                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
+                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+        super.onCreate(bundle);
+
+        window.setFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
+                WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+
+        ActivityManager activityManager =
+                (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+        ConfigurationInfo info = activityManager.getDeviceConfigurationInfo();
+
+        mVersion = (info.reqGlEsVersion & 0xffff0000) >> 16;
+
+        new Thread() {
+            @Override
+            public void run() {
+                runIterations(mVersion);
+            }
+        }.start();
+    }
+
+     /**
+     * Wait for this activity to finish gathering information
+     */
+    public void waitForActivityToFinish() {
+        try {
+            mDone.await();
+        } catch (InterruptedException e) {
+            // just move on
+        }
+    }
+
+    private void runIterations(int glVersion) {
+        for (int i = 1; i <= glVersion; i++) {
+            final CountDownLatch done = new CountDownLatch(1);
+            final int version = i;
+            GlesStubActivity.this.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setContentView(new GlesSurfaceView(GlesStubActivity.this, version, done));
+                }
+            });
+            try {
+                done.await();
+            } catch (InterruptedException e) {
+                // just move on
+            }
+        }
+        mDone.countDown();
+    }
+
+    int getGlVersion() {
+        return mVersion;
+    }
+
+    String[] getOpenGlExtensions() {
+        return mOpenGlExtensions.toArray(new String[mOpenGlExtensions.size()]);
+    }
+
+    void addOpenGlExtension(String openGlExtension) {
+        mOpenGlExtensions.add(openGlExtension);
+    }
+
+    String[] getCompressedTextureFormats() {
+        return mFormats.toArray(new String[mFormats.size()]);
+    }
+
+    void addCompressedTextureFormat(String format) {
+        mFormats.add(format);
+    }
+
+    String getVendor() {
+        return mGraphicsVendor;
+    }
+
+    void setVendor(String vendor) {
+        mGraphicsVendor = vendor;
+    }
+
+    String getRenderer() {
+        return mGraphicsRenderer;
+    }
+
+    void setRenderer(String renderer) {
+        mGraphicsRenderer = renderer;
+    }
+
+    static class GlesSurfaceView extends GLSurfaceView {
+
+        public GlesSurfaceView(GlesStubActivity parent, int glVersion, CountDownLatch done) {
+            super(parent);
+
+            if (glVersion > 1) {
+                // Default is 1 so only set if bigger than 1
+                setEGLContextClientVersion(glVersion);
+            }
+            setRenderer(new OpenGlesRenderer(parent, glVersion, done));
+        }
+    }
+
+    static class OpenGlesRenderer implements GLSurfaceView.Renderer {
+
+        private final GlesStubActivity mParent;
+        private final int mGlVersion;
+        private final CountDownLatch mDone;
+
+        OpenGlesRenderer(GlesStubActivity parent, int glVersion, CountDownLatch done) {
+            mParent = parent;
+            mGlVersion = glVersion;
+            mDone = done;
+        }
+
+        @Override
+        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+            String extensions;
+            String vendor;
+            String renderer;
+            if (mGlVersion == 2) {
+                extensions = GLES20.glGetString(GLES20.GL_EXTENSIONS);
+                vendor = GLES20.glGetString(GLES20.GL_VENDOR);
+                renderer = GLES20.glGetString(GLES20.GL_RENDERER);
+            } else if (mGlVersion == 3) {
+                extensions = GLES30.glGetString(GLES30.GL_EXTENSIONS);
+                vendor = GLES30.glGetString(GLES30.GL_VENDOR);
+                renderer = GLES30.glGetString(GLES30.GL_RENDERER);
+            } else {
+                extensions = gl.glGetString(GL10.GL_EXTENSIONS);
+                vendor = gl.glGetString(GL10.GL_VENDOR);
+                renderer = gl.glGetString(GL10.GL_RENDERER);
+            }
+            mParent.setVendor(vendor);
+            mParent.setRenderer(renderer);
+            Scanner scanner = new Scanner(extensions);
+            scanner.useDelimiter(" ");
+            while (scanner.hasNext()) {
+                String ext = scanner.next();
+                mParent.addOpenGlExtension(ext);
+                if (ext.contains("texture")) {
+                    if (ext.contains("compression") || ext.contains("compressed")) {
+                        mParent.addCompressedTextureFormat(ext);
+                    }
+                }
+            }
+            scanner.close();
+            mDone.countDown();
+        }
+
+        @Override
+        public void onSurfaceChanged(GL10 gl, int width, int height) {}
+
+        @Override
+        public void onDrawFrame(GL10 gl) {}
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GraphicsDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GraphicsDeviceInfo.java
new file mode 100644
index 0000000..d7dcc08
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GraphicsDeviceInfo.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.os.Bundle;
+
+/**
+ * Graphics device info collector.
+ */
+public final class GraphicsDeviceInfo extends DeviceInfo {
+
+    private static final String LOG_TAG = "GraphicsDeviceInfo";
+
+    @Override
+    protected void collectDeviceInfo() {
+        GlesStubActivity stubActivity = GraphicsDeviceInfo.this.launchActivity(
+                "com.android.compatibility.common.deviceinfo",
+                GlesStubActivity.class,
+                new Bundle());
+        stubActivity.waitForActivityToFinish();
+
+        addResult("gl_version", stubActivity.getGlVersion());
+        addResult("vendor", stubActivity.getVendor());
+        addResult("renderer", stubActivity.getRenderer());
+
+        addArray("gl_texture", stubActivity.getCompressedTextureFormats());
+        addArray("gl_extension", stubActivity.getOpenGlExtensions());
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java
new file mode 100644
index 0000000..40bf754
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Formatter;
+
+/**
+ * Library device info collector.
+ */
+public final class LibraryDeviceInfo extends DeviceInfo {
+
+    private static final String TAG = "LibraryDeviceInfo";
+    private static final int BUFFER_SIZE_BYTES = 4096;
+
+    @Override
+    protected void collectDeviceInfo() {
+        collectSystemLibs();
+        collectVendorLibs();
+        collectFrameworkJars();
+    }
+
+    private void collectSystemLibs() {
+        startArray("lib");
+        collectFileDetails("/system/lib", ".so");
+        endArray();
+    }
+
+    private void collectVendorLibs() {
+        startArray("vendor_lib");
+        collectFileDetails("/system/vendor/lib", ".so");
+        endArray();
+    }
+
+    private void collectFrameworkJars() {
+        startArray("framework_jar");
+        collectFileDetails("/system/framework", ".jar");
+        endArray();
+    }
+
+    private void collectFileDetails(String path, String suffix) {
+        File dir = new File(path);
+        for (File file : dir.listFiles()) {
+            String name = file.getName();
+            if (file.isFile() && name.endsWith(suffix)) {
+                String sha1 = "unknown";
+                try {
+                    sha1 = getSha1sum(file);
+                } catch (IOException e) {
+                    Log.e(TAG, "Failed to hash " + file + ": ", e);
+                }
+                startGroup();
+                addResult("name", name);
+                addResult("sha1", sha1);
+                endGroup();
+            }
+        }
+    }
+
+    private static String getSha1sum(File file) throws IOException {
+        InputStream in = null;
+        try {
+            in = new FileInputStream(file);
+            return sha1(in);
+        } finally {
+            close(in);
+        }
+    }
+
+    private static void close(Closeable s) throws IOException {
+        if (s == null) {
+            return;
+        }
+        s.close();
+    }
+
+    /**
+     * @return the SHA-1 digest of input as a hex string
+     */
+    public static String sha1(InputStream input) throws IOException {
+        try {
+            return toHexString(digest(input, "sha1"));
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static byte[] digest(InputStream in, String algorithm)
+        throws NoSuchAlgorithmException, IOException {
+        MessageDigest digest = MessageDigest.getInstance(algorithm);
+        byte[] buffer = new byte[BUFFER_SIZE_BYTES];
+        while (true) {
+            int read = in.read(buffer);
+            if (read < 0) {
+                break;
+            }
+            digest.update(buffer, 0, read);
+        }
+        return digest.digest();
+    }
+
+    private static String toHexString(byte[] buffer) {
+        Formatter formatter = new Formatter();
+        try {
+            for (byte b : buffer) {
+                formatter.format("%02X", b);
+            }
+            return formatter.toString();
+        } finally {
+            formatter.close();
+        }
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
new file mode 100644
index 0000000..831075f
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+/**
+ * Locale device info collector.
+ */
+public final class LocaleDeviceInfo extends DeviceInfo {
+
+    @Override
+    protected void collectDeviceInfo() {
+
+        String[] locales = getInstrumentation().getContext().getAssets().getLocales();
+        if (locales.length == 0) {
+            // default locale
+            addArray("locale", new String[] {"en_US"});
+        } else {
+            addArray("locale", locales);
+        }
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MediaDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MediaDeviceInfo.java
new file mode 100644
index 0000000..dbe3f48
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MediaDeviceInfo.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.MemoryInfo;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Build;
+
+import android.media.CamcorderProfile;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecProfileLevel;
+import android.media.MediaCodecList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Media information collector.
+ */
+public final class MediaDeviceInfo extends DeviceInfo {
+
+    @Override
+    protected void collectDeviceInfo() {
+
+        startArray("media_codec_info");
+
+        for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
+            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+
+            startGroup();
+            addResult("name", info.getName());
+            addResult("encoder", info.isEncoder());
+
+            startArray("supported_type");
+            for (String type : info.getSupportedTypes()) {
+
+                startGroup();
+                addResult("type", type);
+                if (info.getCapabilitiesForType(type).profileLevels.length > 0) {
+
+                    List<Integer> levelList = new ArrayList<>();
+                    List<Integer> profileList = new ArrayList<>();
+                    startArray("codec_profile_level");
+
+                    for (CodecProfileLevel profileLevel :
+                             info.getCapabilitiesForType(type).profileLevels) {
+                        startGroup();
+                        addResult("level", profileLevel.level);
+                        addResult("profile", profileLevel.profile);
+                        endGroup();
+                    }
+                    endArray(); // codec_profile_level
+                }
+                endGroup();
+            }
+            endArray();
+            endGroup();
+        }
+
+        endArray(); // media_codec_profile
+    }
+
+    static int[] toIntArray(List<Integer> integerList) {
+        int[] intArray = new int[integerList.size()];
+        for (int i = 0; i < integerList.size(); i++) {
+            intArray[i] = integerList.get(i);
+        }
+        return intArray;
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MemoryDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MemoryDeviceInfo.java
new file mode 100644
index 0000000..d5a12b4
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MemoryDeviceInfo.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.MemoryInfo;
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.compatibility.common.deviceinfo.DeviceInfo;
+
+/**
+ * MemoryDeviceInfo collector.
+ */
+public final class MemoryDeviceInfo extends DeviceInfo {
+
+    @Override
+    protected void collectDeviceInfo() {
+        ActivityManager activityManager = (ActivityManager)getInstrumentation()
+                .getTargetContext().getSystemService(Context.ACTIVITY_SERVICE);
+        addResult("low_ram_device", activityManager.isLowRamDevice());
+        addResult("memory_class", activityManager.getMemoryClass());
+        addResult("large_memory_class", activityManager.getLargeMemoryClass());
+
+        MemoryInfo memoryInfo = new MemoryInfo();
+        activityManager.getMemoryInfo(memoryInfo);
+        addResult("total_memory", memoryInfo.totalMem);
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
index 4d9ad46..0dd24be 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
@@ -19,12 +19,12 @@
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 
-import com.android.compatibility.common.deviceinfo.DeviceInfoActivity;
+import com.android.compatibility.common.deviceinfo.DeviceInfo;
 
 /**
  * PackageDeviceInfo collector.
  */
-public class PackageDeviceInfo extends DeviceInfoActivity {
+public class PackageDeviceInfo extends DeviceInfo {
 
     private static final String PACKAGE = "package";
     private static final String NAME = "name";
@@ -34,7 +34,7 @@
 
     @Override
     protected void collectDeviceInfo() {
-        PackageManager pm = this.getPackageManager();
+        PackageManager pm = getContext().getPackageManager();
         startArray(PACKAGE);
         for (PackageInfo pkg : pm.getInstalledPackages(0)) {
             startGroup();
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PropertyDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PropertyDeviceInfo.java
new file mode 100644
index 0000000..1844b37
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PropertyDeviceInfo.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * System property info collector.
+ */
+public final class PropertyDeviceInfo extends DeviceInfo {
+
+    private static final String LOG_TAG = "PropertyDeviceInfo";
+
+    @Override
+    protected void collectDeviceInfo() {
+        try {
+            collectRoProperties();
+        } catch (IOException e) {
+            Log.w(LOG_TAG, "Failed to collect properties", e);
+        }
+    }
+
+    private void collectRoProperties() throws IOException {
+        startArray("ro_property");
+        Pattern pattern = Pattern.compile("\\[(ro.+)\\]: \\[(.+)\\]");
+        Scanner scanner = null;
+        try {
+            Process getprop = new ProcessBuilder("getprop").start();
+            scanner = new Scanner(getprop.getInputStream());
+            while (scanner.hasNextLine()) {
+                String line = scanner.nextLine();
+                Matcher matcher = pattern.matcher(line);
+                if (matcher.matches()) {
+                    String name = matcher.group(1);
+                    String value = matcher.group(2);
+
+                    startGroup();
+                    addResult("name", name);
+                    addResult("value", value);
+                    endGroup();
+                }
+            }
+        } finally {
+            endArray();
+            if (scanner != null) {
+                scanner.close();
+            }
+        }
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ScreenDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ScreenDeviceInfo.java
new file mode 100644
index 0000000..5524531
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ScreenDeviceInfo.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+
+/**
+ * Screen device info collector.
+ */
+public final class ScreenDeviceInfo extends DeviceInfo {
+
+    @Override
+    protected void collectDeviceInfo() {
+
+        DisplayMetrics metrics = new DisplayMetrics();
+        WindowManager windowManager =
+                (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+        Display display = windowManager.getDefaultDisplay();
+        display.getRealMetrics(metrics);
+
+        addResult("width_pixels", metrics.widthPixels);
+        addResult("height_pixels", metrics.heightPixels);
+        addResult("x_dpi", metrics.xdpi);
+        addResult("y_dpi", metrics.ydpi);
+        addResult("density", metrics.density);
+        addResult("density_dpi", metrics.densityDpi);
+
+        Configuration configuration = getContext().getResources().getConfiguration();
+        addResult("screen_size", getScreenSize(configuration));
+        addResult("smallest_screen_width_dp", configuration.smallestScreenWidthDp);
+    }
+
+    private static String getScreenSize(Configuration configuration) {
+        int screenLayout = configuration.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
+        String screenSize = String.format("0x%x", screenLayout);
+        switch (screenLayout) {
+            case Configuration.SCREENLAYOUT_SIZE_SMALL:
+                screenSize = "small";
+                break;
+
+            case Configuration.SCREENLAYOUT_SIZE_NORMAL:
+                screenSize = "normal";
+                break;
+
+            case Configuration.SCREENLAYOUT_SIZE_LARGE:
+                screenSize = "large";
+                break;
+
+            case Configuration.SCREENLAYOUT_SIZE_XLARGE:
+                screenSize = "xlarge";
+                break;
+
+            case Configuration.SCREENLAYOUT_SIZE_UNDEFINED:
+                screenSize = "undefined";
+                break;
+        }
+        return screenSize;
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/StorageDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/StorageDeviceInfo.java
new file mode 100644
index 0000000..823b355
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/StorageDeviceInfo.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+/**
+ * Storage device info collector.
+ */
+public class StorageDeviceInfo extends DeviceInfo {
+    private static final String TAG = "StorageDeviceInfo";
+
+    @Override
+    protected void collectDeviceInfo() {
+        int total = 0;
+        total = Math.max(total, getContext().getExternalCacheDirs().length);
+        total = Math.max(total, getContext().getExternalFilesDirs(null).length);
+        total = Math.max(
+                total, getContext().getExternalFilesDirs(Environment.DIRECTORY_PICTURES).length);
+        total = Math.max(total, getContext().getObbDirs().length);
+
+        int emulated = 0;
+        int physical = 0;
+        if (Environment.isExternalStorageEmulated()) {
+            if (total == 1) {
+                emulated = 1;
+            } else {
+                emulated = 1;
+                physical = total - 1;
+            }
+        } else {
+            physical = total;
+        }
+
+        addResult("num_physical", physical);
+        addResult("num_emulated", emulated);
+
+        addArray("raw_partition", scanPartitions());
+    }
+
+    private String[] scanPartitions() {
+        List<String> partitionList = new ArrayList<>();
+        try {
+            Process df = new ProcessBuilder("df").start();
+            Scanner scanner = new Scanner(df.getInputStream());
+            try {
+                while (scanner.hasNextLine()) {
+                   partitionList.add(scanner.nextLine());
+                }
+            } finally {
+                scanner.close();
+            }
+        } catch (Exception e) {
+            Log.w(TAG, Log.getStackTraceString(e));
+        }
+        return partitionList.toArray(new String[partitionList.size()]);
+    }
+
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/UserDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/UserDeviceInfo.java
new file mode 100644
index 0000000..2886e23
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/UserDeviceInfo.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.os.UserManager;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * User device info collector.
+ */
+public final class UserDeviceInfo extends DeviceInfo {
+
+    @Override
+    protected void collectDeviceInfo() {
+        addResult("max_supported_users", getMaxSupportedUsers());
+    }
+
+    private int getMaxSupportedUsers() {
+        try {
+            Method method = UserManager.class.getMethod("getMaxSupportedUsers");
+            return (Integer) method.invoke(null);
+        } catch (ClassCastException |
+                NoSuchMethodException |
+                InvocationTargetException |
+                IllegalAccessException e) {}
+        return -1;
+    }
+}
diff --git a/common/device-side/device-info/tests/Android.mk b/common/device-side/device-info/tests/Android.mk
index e24c5c1..a8d9e038 100644
--- a/common/device-side/device-info/tests/Android.mk
+++ b/common/device-side/device-info/tests/Android.mk
@@ -27,4 +27,3 @@
 LOCAL_MODULE := compatibility-device-info-tests
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
-
diff --git a/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/DeviceInfoActivityTest.java b/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/DeviceInfoActivityTest.java
deleted file mode 100644
index d092f4e..0000000
--- a/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/DeviceInfoActivityTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.deviceinfo;
-
-import android.test.ActivityInstrumentationTestCase2;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-/**
- * Test for {@link DeviceInfoActivity}.
- */
-public class DeviceInfoActivityTest extends ActivityInstrumentationTestCase2<TestDeviceInfo> {
-
-    private static final String EXPECTED_FILE_PATH =
-            "/storage/emulated/0/device-info-files/TestDeviceInfo.deviceinfo.json";
-
-    private TestDeviceInfo mActivity;
-
-    public DeviceInfoActivityTest() {
-        super(TestDeviceInfo.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // Start the activity and get a reference to it.
-        mActivity = getActivity();
-        // Wait for the activity to finish.
-        mActivity.waitForActivityToFinish();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mActivity = null;
-        super.tearDown();
-    }
-
-    public void testJsonFile() throws IOException {
-        String resultFilePath = mActivity.getResultFilePath();
-        // Check file path exist
-        assertNotNull("Expected a non-null resultFilePath", resultFilePath);
-        // Check file path location
-        assertEquals("Incorrect file path", EXPECTED_FILE_PATH, resultFilePath);
-        // Check json file content
-        String jsonContent = readFile(resultFilePath);
-        assertEquals("Incorrect json output", ExampleObjects.testDeviceInfoJson(), jsonContent);
-    }
-
-    private String readFile(String filePath) throws IOException {
-        InputStreamReader inputStreamReader = new InputStreamReader(
-                new FileInputStream(filePath), "UTF-8");
-        StringBuilder stringBuilder = new StringBuilder();
-        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
-        String line;
-        while((line = bufferedReader.readLine()) != null) {
-            stringBuilder.append(line);
-            stringBuilder.append('\n');
-        }
-        bufferedReader.close();
-        return stringBuilder.toString();
-    }
-}
-
diff --git a/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/DeviceInfoTest.java b/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/DeviceInfoTest.java
new file mode 100644
index 0000000..3459d59
--- /dev/null
+++ b/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/DeviceInfoTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.test.AndroidTestCase;
+import android.test.ActivityInstrumentationTestCase2;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * Test for {@link DeviceInfo}.
+ */
+public class DeviceInfoTest extends AndroidTestCase {
+
+    private static final String EXPECTED_FILE_PATH =
+            "/storage/emulated/0/device-info-files/TestDeviceInfo.deviceinfo.json";
+
+    private TestDeviceInfo testDeviceInfo = new TestDeviceInfo();
+
+    public void testJsonFile() throws Exception {
+        testDeviceInfo.setUp();
+        testDeviceInfo.testCollectDeviceInfo();
+        String resultFilePath = testDeviceInfo.getResultFilePath();
+        // Check file path exist
+        assertNotNull("Expected a non-null resultFilePath", resultFilePath);
+        // Check file path location
+        assertEquals("Incorrect file path", EXPECTED_FILE_PATH, resultFilePath);
+        // Check json file content
+        String jsonContent = readFile(resultFilePath);
+        assertEquals("Incorrect json output", ExampleObjects.testDeviceInfoJson(), jsonContent);
+    }
+
+    private String readFile(String filePath) throws IOException {
+        InputStreamReader inputStreamReader = new InputStreamReader(
+                new FileInputStream(filePath), "UTF-8");
+        StringBuilder stringBuilder = new StringBuilder();
+        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+        String line;
+        while((line = bufferedReader.readLine()) != null) {
+            stringBuilder.append(line);
+            stringBuilder.append('\n');
+        }
+        bufferedReader.close();
+        return stringBuilder.toString();
+    }
+}
\ No newline at end of file
diff --git a/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/ExampleObjects.java b/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/ExampleObjects.java
index 570bdd5..9411cd2 100644
--- a/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/ExampleObjects.java
+++ b/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/ExampleObjects.java
@@ -16,12 +16,12 @@
 package com.android.compatibility.common.deviceinfo;
 
 /**
- * Example Objects for {@link DeviceInfoActivity} test package.
+ * Example Objects for {@link DeviceInfo} test package.
  */
 public final class ExampleObjects {
 
-    // Must match DeviceInfoActivity.MAX_STRING_VALUE_LENGTH and
-    // DeviceInfoActivity.MAX_ARRAY_LENGTH
+    // Must match DeviceInfo.MAX_STRING_VALUE_LENGTH and
+    // DeviceInfo.MAX_ARRAY_LENGTH
     private static final int MAX_LENGTH = 1000;
 
     private static final String TEST_DEVICE_INFO_JSON = "{\n" +
diff --git a/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/SampleDeviceInfo.java b/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/SampleDeviceInfo.java
deleted file mode 100644
index 7da9951..0000000
--- a/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/SampleDeviceInfo.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.deviceinfo;
-
-import android.os.Bundle;
-
-import java.lang.StringBuilder;
-
-/**
- * Sample device info collector.
- */
-public class SampleDeviceInfo extends DeviceInfoActivity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
-    protected void collectDeviceInfo() {
-        boolean[] booleans = {Boolean.TRUE, Boolean.FALSE};
-        double[] doubles = {Double.MAX_VALUE, Double.MIN_VALUE};
-        int[] ints = {Integer.MAX_VALUE, Integer.MIN_VALUE};
-        long[] longs = {Long.MAX_VALUE, Long.MIN_VALUE};
-
-        // Group Foo
-        startGroup("foo");
-        addResult("foo_boolean", Boolean.TRUE);
-
-        // Group Bar
-        startGroup("bar");
-        addArray("bar_string", new String[] {
-                "bar-string-1",
-                "bar-string-2",
-                "bar-string-3"});
-
-        addArray("bar_boolean", booleans);
-        addArray("bar_double", doubles);
-        addArray("bar_int", ints);
-        addArray("bar_long", longs);
-        endGroup(); // bar
-
-        addResult("foo_double", Double.MAX_VALUE);
-        addResult("foo_int", Integer.MAX_VALUE);
-        addResult("foo_long", Long.MAX_VALUE);
-        addResult("foo_string", "foo-string");
-
-        StringBuilder sb = new StringBuilder();
-        int[] arr = new int[1001];
-        for (int i = 0; i < 1001; i++) {
-            sb.append("a");
-            arr[i] = i;
-        }
-        addResult("long_string", sb.toString());
-        addArray("long_int_array", arr);
-
-        endGroup(); // foo
-    }
-}
-
diff --git a/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/TestDeviceInfo.java b/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/TestDeviceInfo.java
index 7f82942..1360312 100644
--- a/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/TestDeviceInfo.java
+++ b/common/device-side/device-info/tests/src/com/android/compatibility/common/deviceinfo/TestDeviceInfo.java
@@ -18,15 +18,17 @@
 import android.os.Bundle;
 
 import java.lang.StringBuilder;
+import java.util.HashSet;
 
 /**
- * Collector for testing DeviceInfoActivity
+ * Collector for testing DeviceInfo
  */
-public class TestDeviceInfo extends DeviceInfoActivity {
+public class TestDeviceInfo extends DeviceInfo {
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    protected void setUp() throws Exception {
+        mActivityList = new HashSet<String>();
+        mActivityList.add(getClass().getName());
     }
 
     @Override
@@ -82,4 +84,7 @@
         addResult("max_length_string", sb.toString());
         addArray("max_num_ints", arr);
     }
+
+    @Override
+    void sendStatus() {}
 }
diff --git a/common/device-side/device-setup/Android.mk b/common/device-side/device-setup/Android.mk
deleted file mode 100644
index bc7c504..0000000
--- a/common/device-side/device-setup/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := compatibility-device-setup_v2
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-###############################################################################
-# Build the tests
-###############################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, tests/src)
-
-LOCAL_JAVA_LIBRARIES := junit
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := compatibility-device-setup-tests_v2
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/device-side/device-setup/src/com/android/compatibility/common/devicesetup/DeviceInfoConstants.java b/common/device-side/device-setup/src/com/android/compatibility/common/devicesetup/DeviceInfoConstants.java
deleted file mode 100644
index 7b19b00..0000000
--- a/common/device-side/device-setup/src/com/android/compatibility/common/devicesetup/DeviceInfoConstants.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.compatibility.common.devicesetup;
-
-/**
- * Constants for device info attributes to be sent as instrumentation keys.
- */
-public interface DeviceInfoConstants {
-
-    public static final String BUILD_ABI = "buildAbi";
-    public static final String BUILD_ABI2 = "buildAbi2";
-    public static final String BUILD_BOARD = "buildBoard";
-    public static final String BUILD_BRAND = "buildBrand";
-    public static final String BUILD_DEVICE = "buildDevice";
-    public static final String BUILD_FINGERPRINT = "buildFingerprint";
-    public static final String BUILD_ID = "buildId";
-    public static final String BUILD_MANUFACTURER = "buildManufacturer";
-    public static final String BUILD_MODEL = "buildModel";
-    public static final String BUILD_TAGS = "buildTags";
-    public static final String BUILD_TYPE = "buildType";
-    public static final String BUILD_VERSION = "buildVersion";
-
-    public static final String FEATURES = "features";
-
-    public static final String GRAPHICS_RENDERER = "graphicsRenderer";
-    public static final String GRAPHICS_VENDOR = "graphicsVendor";
-
-    public static final String IMEI = "imei";
-    public static final String IMSI = "imsi";
-
-    public static final String KEYPAD = "keypad";
-
-    public static final String LOCALES = "locales";
-
-    public static final String MULTI_USER = "multiUser";
-
-    public static final String NAVIGATION = "navigation";
-    public static final String NETWORK = "network";
-
-    public static final String OPEN_GL_ES_VERSION = "openGlEsVersion";
-    public static final String OPEN_GL_EXTENSIONS = "openGlExtensions";
-    public static final String OPEN_GL_COMPRESSED_TEXTURE_FORMATS =
-            "openGlCompressedTextureFormats";
-
-    public static final String PARTITIONS = "partitions";
-    public static final String PHONE_NUMBER = "phoneNumber";
-    public static final String PROCESSES = "processes";
-    public static final String PRODUCT_NAME = "productName";
-
-    public static final String RESOLUTION = "resolution";
-
-    public static final String SCREEN_DENSITY = "screenDensity";
-    public static final String SCREEN_DENSITY_BUCKET = "screenDensityBucket";
-    public static final String SCREEN_DENSITY_X = "screenDensityX";
-    public static final String SCREEN_DENSITY_Y = "screenDensityY";
-    public static final String SCREEN_SIZE = "screenSize";
-    public static final String SERIAL_NUMBER = "deviceId";
-    public static final String STORAGE_DEVICES = "storageDevices";
-    public static final String SYS_LIBRARIES = "systemLibraries";
-
-    public static final String TOUCH = "touch";
-
-    public static final String VERSION_RELEASE = "versionRelease";
-    public static final String VERSION_SDK_INT = "versionSdkInt";
-}
diff --git a/common/device-side/device-setup/tests/src/com/android/compatibility/common/devicesetup/DeviceSetupTest.java b/common/device-side/device-setup/tests/src/com/android/compatibility/common/devicesetup/DeviceSetupTest.java
deleted file mode 100644
index ee55a66..0000000
--- a/common/device-side/device-setup/tests/src/com/android/compatibility/common/devicesetup/DeviceSetupTest.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.compatibility.common.devicesetup;
-
-import junit.framework.TestCase;
-
-public class DeviceSetupTest extends TestCase {
-
-    // TODO(stuartscott): Add tests when there is something to test.
-
-}
diff --git a/common/device-side/preconditions/Android.mk b/common/device-side/preconditions/Android.mk
new file mode 100644
index 0000000..75c981b
--- /dev/null
+++ b/common/device-side/preconditions/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-devicesidelib
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := compatibility-device-preconditions
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/ExternalStorageHelper.java b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/ExternalStorageHelper.java
new file mode 100644
index 0000000..f398ea8
--- /dev/null
+++ b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/ExternalStorageHelper.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.preconditions;
+
+import android.os.Environment;
+
+/**
+ * ExternalStorageHelper is used to check whether the device's external storage is readable
+ * and writeable.
+ */
+public class ExternalStorageHelper {
+
+    /* Checks if external storage is available for read and write */
+    public static boolean isExternalStorageWritable() {
+        String state = Environment.getExternalStorageState();
+        return Environment.MEDIA_MOUNTED.equals(state);
+    }
+
+    /* Checks if external storage is available to at least read */
+    public static boolean isExternalStorageReadable() {
+        String state = Environment.getExternalStorageState();
+        return (Environment.MEDIA_MOUNTED.equals(state) ||
+                Environment.MEDIA_MOUNTED_READ_ONLY.equals(state));
+    }
+
+}
diff --git a/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/ScreenLockHelper.java b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/ScreenLockHelper.java
new file mode 100644
index 0000000..d2380af
--- /dev/null
+++ b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/ScreenLockHelper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.preconditions;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+
+/**
+ * ScreenLockHelper is used to check whether the device is protected by a locked screen.
+ */
+public class ScreenLockHelper {
+
+    /*
+     * This helper returns false for the Screen Lock set to 'Swipe' or 'None', as it seems there
+     * is no way to programmatically distinguish between the two.
+     */
+    public static boolean isDeviceSecure(Context context) {
+        KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
+        return km.isDeviceSecure();
+    }
+
+}
diff --git a/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/WifiHelper.java b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/WifiHelper.java
new file mode 100644
index 0000000..70a4b03
--- /dev/null
+++ b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/WifiHelper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.preconditions;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+
+/**
+ * WifiHelper is used to check whether the device is connected to WiFi.
+ * This is required for a subset of the CTS test modules.
+ */
+public class WifiHelper {
+
+    public static boolean isWifiConnected(Context context) {
+        ConnectivityManager cm = (ConnectivityManager)
+                context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        NetworkInfo wifiNetworkInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+        return wifiNetworkInfo.isConnected();
+    }
+
+}
diff --git a/common/device-side/test-app/Android.mk b/common/device-side/test-app/Android.mk
new file mode 100755
index 0000000..6adce97
--- /dev/null
+++ b/common/device-side/test-app/Android.mk
@@ -0,0 +1,40 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build an APK which contains the device-side libraries and their tests,
+# this then gets instrumented in order to test the aforementioned libraries.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test\
+    compatibility-common-util-devicesidelib\
+    compatibility-device-info-tests\
+    compatibility-device-info\
+    compatibility-device-util-tests\
+    compatibility-device-util
+
+LOCAL_PACKAGE_NAME := CompatibilityTestApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/common/device-side/test-app/AndroidManifest.xml b/common/device-side/test-app/AndroidManifest.xml
new file mode 100755
index 0000000..9c857f0
--- /dev/null
+++ b/common/device-side/test-app/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.compatibility.common">
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="com.android.compatibility.common.deviceinfo.TestDeviceInfo" />
+    </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.compatibility.common"
+                     android:label="Tests for device-side Compatibility common code">
+    </instrumentation>
+
+</manifest>
+
diff --git a/common/device-side/test-app/run_tests.sh b/common/device-side/test-app/run_tests.sh
new file mode 100755
index 0000000..fa5f553
--- /dev/null
+++ b/common/device-side/test-app/run_tests.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# Copyright (C) 2015 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.
+
+CTS_DIR=$(dirname ${0})/../../..
+source ${CTS_DIR}/test_defs.sh
+
+if [ `adb devices | wc -l` -lt 2 ]; then
+    echo "NO DEVICES/EMULATORS AVAILABLE. CONNECT ONE."
+    exit 1
+fi
+
+# Take the last serial in the list of devices
+SERIAL=`adb devices | egrep -o "^\w+" | tail -n1`
+if [ -z ${SERIAL} ]; then
+    echo "FAILED TO GET ADB DEVICE SERIAL FOR TEST. EXITING"
+    exit 1
+fi
+
+echo "Running device side tests on device: ${SERIAL}"
+
+APK=${ANDROID_PRODUCT_OUT}/data/app/CompatibilityTestApp/CompatibilityTestApp.apk
+checkFile ${APK}
+
+COMMON_PACKAGE=com.android.compatibility.common
+RUNNER=android.support.test.runner.AndroidJUnitRunner
+# TODO [2015-12-09 kalle] Fail & exit on failing install?
+adb -s ${SERIAL} install -r -g ${APK}
+build_jar_path ${JAR_DIR} "${JARS}"
+java $RDBG_FLAG -cp ${JAR_PATH} ${TF_CONSOLE} run singleCommand instrument --serial ${SERIAL} --package ${COMMON_PACKAGE} --runner ${RUNNER}
+adb -s ${SERIAL} uninstall ${COMMON_PACKAGE}
diff --git a/common/device-side/util/Android.mk b/common/device-side/util/Android.mk
index c8104bf..350c2db 100644
--- a/common/device-side/util/Android.mk
+++ b/common/device-side/util/Android.mk
@@ -12,34 +12,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-devicesidelib_v2
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-devicesidelib
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_MODULE := compatibility-device-util_v2
+LOCAL_MODULE := compatibility-device-util
 
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
-################################################################################
-# Build the tests
-###############################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, tests/src)
-
-LOCAL_JAVA_LIBRARIES := junit
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := compatibility-device-util-tests_v2
-
-include $(BUILD_HOST_JAVA_LIBRARY)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
index 273cdf5..d87ebbc 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
@@ -22,6 +22,10 @@
 
 import com.android.compatibility.common.util.ReportLog;
 
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
 /**
  * Handles adding results to the report for device side tests.
  *
@@ -30,13 +34,20 @@
  */
 public class DeviceReportLog extends ReportLog {
     private static final String TAG = DeviceReportLog.class.getSimpleName();
-    private static final String RESULT = "RESULT";
+    private static final String RESULT = "COMPATIBILITY_TEST_RESULT";
+    private static final int INST_STATUS_ERROR = -1;
     private static final int INST_STATUS_IN_PROGRESS = 2;
 
     public void submit(Instrumentation instrumentation) {
-        Log.i(TAG, "submit");
-        Bundle output = new Bundle();
-        output.putSerializable(RESULT, this);
-        instrumentation.sendStatus(INST_STATUS_IN_PROGRESS, output);
+        Log.i(TAG, "Submit");
+        try {
+            Bundle output = new Bundle();
+            output.putString(RESULT, serialize(this));
+            instrumentation.sendStatus(INST_STATUS_IN_PROGRESS, output);
+        } catch (IllegalArgumentException | IllegalStateException | XmlPullParserException
+                | IOException e) {
+            Log.e(TAG, "Submit Failed", e);
+            instrumentation.sendStatus(INST_STATUS_ERROR, null);
+        }
     }
 }
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DynamicConfigDeviceSide.java b/common/device-side/util/src/com/android/compatibility/common/util/DynamicConfigDeviceSide.java
new file mode 100644
index 0000000..303efec
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/DynamicConfigDeviceSide.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import android.os.Environment;
+import android.util.Log;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Load dynamic config for device side test cases
+ */
+public class DynamicConfigDeviceSide extends DynamicConfig {
+    private static String LOG_TAG = DynamicConfigDeviceSide.class.getSimpleName();
+
+    public DynamicConfigDeviceSide(String moduleName) throws XmlPullParserException, IOException {
+        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+            throw new IOException("External storage is not mounted");
+        }
+        File configFile = getConfigFile(new File(CONFIG_FOLDER_ON_DEVICE), moduleName);
+        initConfigFromXml(configFile);
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/EvaluateJsResultPollingCheck.java b/common/device-side/util/src/com/android/compatibility/common/util/EvaluateJsResultPollingCheck.java
index 521dc40..61f1bb8 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/EvaluateJsResultPollingCheck.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/EvaluateJsResultPollingCheck.java
@@ -18,7 +18,7 @@
 
 import android.webkit.ValueCallback;
 
-public class EvaluateJsResultPollingCheck  extends PollingCheck
+public class EvaluateJsResultPollingCheck extends PollingCheck
         implements ValueCallback<String> {
     private String mActualResult;
     private String mExpectedResult;
diff --git a/common/device-side/util/tests/Android.mk b/common/device-side/util/tests/Android.mk
new file mode 100644
index 0000000..fa7424d
--- /dev/null
+++ b/common/device-side/util/tests/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := compatibility-device-util-tests
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java
new file mode 100644
index 0000000..7dbece0
--- /dev/null
+++ b/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.compatibility.common.util;
+
+import android.app.Instrumentation;
+import android.os.Bundle;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@line DeviceReportLog}.
+ */
+public class DeviceReportTest extends TestCase {
+
+    /**
+     * A stub of {@link Instrumentation}
+     */
+    public class TestInstrumentation extends Instrumentation {
+
+        private int mResultCode = -1;
+        private Bundle mResults = null;
+
+        @Override
+        public void sendStatus(int resultCode, Bundle results) {
+            mResultCode = resultCode;
+            mResults = results;
+        }
+    }
+
+    private static final int RESULT_CODE = 2;
+    private static final String RESULT_KEY = "COMPATIBILITY_TEST_RESULT";
+    private static final String TEST_MESSAGE_1 = "Foo";
+    private static final double TEST_VALUE_1 = 3;
+    private static final ResultType TEST_TYPE_1 = ResultType.HIGHER_BETTER;
+    private static final ResultUnit TEST_UNIT_1 = ResultUnit.SCORE;
+    private static final String TEST_MESSAGE_2 = "Bar";
+    private static final double TEST_VALUE_2 = 5;
+    private static final ResultType TEST_TYPE_2 = ResultType.LOWER_BETTER;
+    private static final ResultUnit TEST_UNIT_2 = ResultUnit.COUNT;
+
+    public void testSubmit() throws Exception {
+        DeviceReportLog log = new DeviceReportLog();
+        log.addValue(TEST_MESSAGE_1, TEST_VALUE_1, TEST_TYPE_1, TEST_UNIT_1);
+        log.setSummary(TEST_MESSAGE_2, TEST_VALUE_2, TEST_TYPE_2, TEST_UNIT_2);
+        TestInstrumentation inst = new TestInstrumentation();
+        log.submit(inst);
+        assertEquals("Incorrect result code", RESULT_CODE, inst.mResultCode);
+        assertNotNull("Bundle missing", inst.mResults);
+        String metrics = inst.mResults.getString(RESULT_KEY);
+        assertNotNull("Metrics missing", metrics);
+        ReportLog result = ReportLog.parse(metrics);
+        assertNotNull("Metrics could not be decoded", result);
+    }
+}
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceUtilTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceUtilTest.java
deleted file mode 100644
index a7e81d7..0000000
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceUtilTest.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.compatibility.common.util;
-
-import junit.framework.TestCase;
-
-public class DeviceUtilTest extends TestCase {
-
-}
diff --git a/common/host-side/java-scanner/Android.mk b/common/host-side/java-scanner/Android.mk
deleted file mode 100644
index 7c101ff..0000000
--- a/common/host-side/java-scanner/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := compatibility-common-util-hostsidelib_v2
-
-LOCAL_JAR_MANIFEST := MANIFEST.mf
-
-LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
-
-LOCAL_MODULE := compatibility-java-scanner_v2
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-################################################################################
-# Build the tests
-###############################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, tests/src)
-
-LOCAL_JAVA_LIBRARIES := compatibility-tradefed_v2 compatibility-java-scanner_v2 junit
-
-LOCAL_MODULE := compatibility-java-scanner-tests_v2
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/java-scanner/MANIFEST.mf b/common/host-side/java-scanner/MANIFEST.mf
deleted file mode 100644
index 975b1ef..0000000
--- a/common/host-side/java-scanner/MANIFEST.mf
+++ /dev/null
@@ -1,3 +0,0 @@
-Manifest-Version: 1.0
-Main-Class: com.android.compatibility.common.scanner.JavaScanner
-Class-Path: compatibility-common-util-hostsidelib_v2.jar
diff --git a/common/host-side/java-scanner/src/com/android/compatibility/common/scanner/JavaScanner.java b/common/host-side/java-scanner/src/com/android/compatibility/common/scanner/JavaScanner.java
deleted file mode 100644
index f3f8a49..0000000
--- a/common/host-side/java-scanner/src/com/android/compatibility/common/scanner/JavaScanner.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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.compatibility.common.scanner;
-
-import com.android.compatibility.common.util.KeyValueArgsParser;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Scans a source directory for java tests and outputs a list of test classes and methods.
- */
-public class JavaScanner {
-
-    static final String[] SOURCE_PATHS = {
-        "./frameworks/base/core/java",
-        "./frameworks/base/test-runner/src",
-        "./external/junit/src",
-        "./development/tools/hosttestlib/src",
-        "./libcore/dalvik/src/main/java",
-        "./common/device-side/util/src",
-        "./common/host-side/tradefed/src",
-        "./common/util/src"
-    };
-    static final String[] CLASS_PATHS = {
-        "./prebuilts/misc/common/tradefed/tradefed-prebuilt.java",
-        "./prebuilts/misc/common/ub-uiautomator/ub-uiautomator.java"
-    };
-    private final File mSourceDir;
-    private final File mDocletDir;
-
-    /**
-     * @param sourceDir The directory holding the source to scan.
-     * @param docletDir The directory holding the doclet (or its jar).
-     */
-    JavaScanner(File sourceDir, File docletDir) {
-        this.mSourceDir = sourceDir;
-        this.mDocletDir = docletDir;
-    }
-
-    int scan() throws Exception {
-        final ArrayList<String> args = new ArrayList<String>();
-        args.add("javadoc");
-        args.add("-doclet");
-        args.add("com.android.compatibility.common.scanner.JavaScannerDoclet");
-        args.add("-sourcepath");
-        args.add(getSourcePath(mSourceDir));
-        args.add("-classpath");
-        args.add(getClassPath());
-        args.add("-docletpath");
-        args.add(mDocletDir.toString());
-        args.addAll(getSourceFiles(mSourceDir));
-
-        // Dont want p to get blocked due to a full pipe.
-        final Process p = new ProcessBuilder(args).redirectErrorStream(true).start();
-        final BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
-        try {
-            String line = null;
-            while ((line = in.readLine()) != null) {
-                if (line.startsWith("suite:") ||
-                    line.startsWith("case:") ||
-                    line.startsWith("test:")) {
-                    System.out.println(line);
-                }
-            }
-        } finally {
-          if (in != null) {
-              in.close();
-          }
-        }
-
-        return p.waitFor();
-    }
-
-    private static String getSourcePath(File sourceDir) {
-        final ArrayList<String> sourcePath = new ArrayList<String>(Arrays.asList(SOURCE_PATHS));
-        sourcePath.add(sourceDir.toString());
-        return join(sourcePath, ":");
-    }
-
-    private static String getClassPath() {
-        return join(Arrays.asList(CLASS_PATHS), ":");
-    }
-
-    private static ArrayList<String> getSourceFiles(File sourceDir) {
-        final ArrayList<String> sourceFiles = new ArrayList<String>();
-        final File[] files = sourceDir.listFiles(new FileFilter() {
-            public boolean accept(File pathname) {
-                return pathname.isDirectory() || pathname.toString().endsWith(".java");
-            }
-        });
-        for (File f : files) {
-            if (f.isDirectory()) {
-                sourceFiles.addAll(getSourceFiles(f));
-            } else {
-                sourceFiles.add(f.toString());
-            }
-        }
-        return sourceFiles;
-    }
-
-    private static String join(List<String> list, String delimiter) {
-        final StringBuilder builder = new StringBuilder();
-        for (String s : list) {
-            builder.append(s);
-            builder.append(delimiter);
-        }
-        // Adding the delimiter each time and then removing the last one at the end is more
-        // efficient than doing a check in each iteration of the loop.
-        return builder.substring(0, builder.length() - delimiter.length());
-    }
-
-    public static void main(String[] args) throws Exception {
-        final HashMap<String, String> argsMap = KeyValueArgsParser.parse(args);
-        final String sourcePath = argsMap.get("-s");
-        final String docletPath = argsMap.get("-d");
-        if (sourcePath == null || docletPath == null) {
-            usage(args);
-        }
-        System.exit(new JavaScanner(new File(sourcePath), new File(docletPath)).scan());
-    }
-
-    private static void usage(String[] args) {
-        System.err.println("Arguments: " + Arrays.toString(args));
-        System.err.println("Usage: javascanner -s SOURCE_DIR -d DOCLET_PATH");
-        System.exit(1);
-    }
-}
diff --git a/common/host-side/java-scanner/src/com/android/compatibility/common/scanner/JavaScannerDoclet.java b/common/host-side/java-scanner/src/com/android/compatibility/common/scanner/JavaScannerDoclet.java
deleted file mode 100644
index 94eccd0..0000000
--- a/common/host-side/java-scanner/src/com/android/compatibility/common/scanner/JavaScannerDoclet.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.compatibility.common.scanner;
-
-import com.sun.javadoc.ClassDoc;
-import com.sun.javadoc.Doclet;
-import com.sun.javadoc.MethodDoc;
-import com.sun.javadoc.RootDoc;
-
-import java.io.PrintWriter;
-
-/**
- * Doclet that scans java files looking for tests.
- *
- * Sample Ouput;
- * suite:com.android.sample.cts
- * case:SampleDeviceTest
- * test:testSharedPreferences
- */
-public class JavaScannerDoclet extends Doclet {
-
-    private static final String JUNIT_TEST_CASE_CLASS_NAME = "junit.framework.testcase";
-
-    public static boolean start(RootDoc root) {
-        ClassDoc[] classes = root.classes();
-        if (classes == null) {
-            return false;
-        }
-
-        PrintWriter writer = new PrintWriter(System.out);
-
-        for (ClassDoc clazz : classes) {
-            if (clazz.isAbstract() || !isValidJUnitTestCase(clazz)) {
-                continue;
-            }
-            writer.append("suite:").println(clazz.containingPackage().name());
-            writer.append("case:").println(clazz.name());
-            for (; clazz != null; clazz = clazz.superclass()) {
-                for (MethodDoc method : clazz.methods()) {
-                    if (method.name().startsWith("test")) {
-                        writer.append("test:").println(method.name());
-                    }
-                }
-            }
-        }
-
-        writer.close();
-        return true;
-    }
-
-    private static boolean isValidJUnitTestCase(ClassDoc clazz) {
-        while ((clazz = clazz.superclass()) != null) {
-            if (JUNIT_TEST_CASE_CLASS_NAME.equals(clazz.qualifiedName().toLowerCase())) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/common/host-side/java-scanner/tests/src/com/android/compatibility/common/scanner/JavaScannerTest.java b/common/host-side/java-scanner/tests/src/com/android/compatibility/common/scanner/JavaScannerTest.java
deleted file mode 100644
index 4159f0e..0000000
--- a/common/host-side/java-scanner/tests/src/com/android/compatibility/common/scanner/JavaScannerTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.compatibility.common.scanner;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-import junit.framework.TestCase;
-
-public class JavaScannerTest extends TestCase {
-
-    private static final String JAR = "out/host/linux-x86/framework/compatibility-java-scanner_v2.jar";
-    private static final String VALID_RESULT =
-        "suite:com.android.test" +
-        "case:ValidTest" +
-        "test:testA";
-
-    private static final String VALID_FILENAME = "ValidTest";
-    private static final String VALID =
-        "package com.android.test;" +
-        "import junit.framework.TestCase;" +
-        "public class ValidTest extends TestCase {" +
-        "  public void testA() throws Exception {" +
-        "    helper();" +
-        "  }" +
-        "  public void helper() {" +
-        "    fail();" +
-        "  }" +
-        "}";
-
-    // TestCases must have TestCase in their hierarchy
-    private static final String INVALID_A_FILENAME = "NotTestCase";
-    private static final String INVALID_A =
-        "package com.android.test;" +
-        "public class NotTestCase {" +
-        "  public void testA() throws Exception {" +
-        "    helper();" +
-        "  }" +
-        "  public void helper() {" +
-        "    fail();" +
-        "  }" +
-        "}";
-
-    // TestCases cant be abstract classes
-    private static final String INVALID_B_FILENAME = "AbstractClass";
-    private static final String INVALID_B =
-        "package com.android.test;" +
-        "import junit.framework.TestCase;" +
-        "public abstract class AbstractClass extends TestCase {" +
-        "  public void testA() throws Exception {" +
-        "    helper();" +
-        "  }" +
-        "  public void helper() {" +
-        "    fail();" +
-        "  }" +
-        "}";
-
-    public void testValidFile() throws Exception {
-        String result = runScanner(VALID_FILENAME, VALID);
-        assertEquals(VALID_RESULT, result);
-    }
-
-    public void testInvalidFileA() throws Exception {
-        assertEquals("", runScanner(INVALID_A_FILENAME, INVALID_A));
-    }
-
-    public void testInvalidFileB() throws Exception {
-        assertEquals("", runScanner(INVALID_B_FILENAME, INVALID_B));
-    }
-
-    private static String runScanner(String filename, String content) throws Exception {
-        final File parent0 = new File(System.getProperty("java.io.tmpdir"));
-        final File parent1 = new File(parent0, "tmp" + System.currentTimeMillis());
-        final File parent2 = new File(parent1, "com");
-        final File parent3 = new File(parent2, "android");
-        final File parent4 = new File(parent3, "test");
-        File f = null;
-        try {
-            parent4.mkdirs();
-            f = new File(parent4, filename + ".java");
-            final PrintWriter out = new PrintWriter(f);
-            out.print(content);
-            out.flush();
-            out.close();
-            ArrayList<String> args = new ArrayList<String>();
-            args.add("java");
-            args.add("-jar");
-            args.add(JAR);
-            args.add("-s");
-            args.add(parent1.toString());
-            args.add("-d");
-            args.add(JAR);
-
-            final Process p = new ProcessBuilder(args).start();
-            final StringBuilder output = new StringBuilder();
-            final BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
-            String line = null;
-            while ((line = in.readLine()) != null) {
-                output.append(line);
-            }
-            int ret = p.waitFor();
-            if (ret == 0) {
-                return output.toString();
-            }
-        } finally {
-            if (f != null) {
-                f.delete();
-            }
-            parent4.delete();
-            parent3.delete();
-            parent2.delete();
-            parent1.delete();
-        }
-        return null;
-    }
-}
diff --git a/common/host-side/manifest-generator/Android.mk b/common/host-side/manifest-generator/Android.mk
index ca08928..b976329 100644
--- a/common/host-side/manifest-generator/Android.mk
+++ b/common/host-side/manifest-generator/Android.mk
@@ -30,4 +30,4 @@
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/common/host-side/manifest-generator/src/com/android/compatibility/common/generator/ManifestGenerator.java b/common/host-side/manifest-generator/src/com/android/compatibility/common/generator/ManifestGenerator.java
index e23e254..7241ada 100644
--- a/common/host-side/manifest-generator/src/com/android/compatibility/common/generator/ManifestGenerator.java
+++ b/common/host-side/manifest-generator/src/com/android/compatibility/common/generator/ManifestGenerator.java
@@ -25,9 +25,11 @@
 
 public class ManifestGenerator {
 
+    private static final String DEFAULT_MIN_SDK = "8";
+
     private static final String USAGE = "Usage: "
         + "manifest-generator -n NAME -p PACKAGE_NAME -o OUTPUT_FILE -i INSTRUMENT_NAME "
-        + "[-r PERMISSION]+ [-a ACTIVITY]+";
+        + "[-s MIN_SDK_VERSION] [-t TARGET_SDK_VERSION] [-r PERMISSION]+ [-a ACTIVITY]+";
     private static final String MANIFEST = "manifest";
     private static final String USES_SDK = "uses-sdk";
     private static final String USES_PERMISSION = "uses-permission";
@@ -38,6 +40,8 @@
     public static void main(String[] args) {
         String pkgName = null;
         String instrumentName = null;
+        String minSdk = DEFAULT_MIN_SDK;
+        String targetSdk = null;
         List<String> permissions = new ArrayList<>();
         List<String> activities = new ArrayList<>();
         String output = null;
@@ -53,6 +57,10 @@
                 instrumentName = args[++i];
             } else if (args[i].equals("-r")) {
                 permissions.add(args[++i]);
+            } else if (args[i].equals("-s")) {
+                minSdk = args[++i];
+            } else if (args[i].equals("-t")) {
+                targetSdk = args[++i];
             }
         }
 
@@ -69,7 +77,7 @@
         FileOutputStream out = null;
         try {
           out = new FileOutputStream(output);
-          generate(out, pkgName, instrumentName, permissions, activities);
+          generate(out, pkgName, instrumentName, minSdk, targetSdk, permissions, activities);
         } catch (Exception e) {
           System.err.println("Couldn't create manifest file");
         } finally {
@@ -84,7 +92,8 @@
     }
 
     /*package*/ static void generate(OutputStream out, String pkgName, String instrumentName,
-            List<String> permissions, List<String> activities) throws Exception {
+            String minSdk, String targetSdk, List<String> permissions, List<String> activities)
+            throws Exception {
         final String ns = null;
         KXmlSerializer serializer = new KXmlSerializer();
         serializer.setOutput(out, "UTF-8");
@@ -94,7 +103,10 @@
         serializer.attribute(ns, "xmlns:android", "http://schemas.android.com/apk/res/android");
         serializer.attribute(ns, "package", pkgName);
         serializer.startTag(ns, USES_SDK);
-        serializer.attribute(ns, "android:minSdkVersion", "8");
+        serializer.attribute(ns, "android:minSdkVersion", minSdk);
+        if (targetSdk != null) {
+            serializer.attribute(ns, "android:targetSdkVersion", targetSdk);
+        }
         serializer.endTag(ns, USES_SDK);
         for (String permission : permissions) {
             serializer.startTag(ns, USES_PERMISSION);
@@ -122,5 +134,4 @@
         System.err.println(USAGE);
         System.exit(1);
     }
-
 }
diff --git a/common/host-side/manifest-generator/tests/run_tests.sh b/common/host-side/manifest-generator/tests/run_tests.sh
new file mode 100755
index 0000000..758589c
--- /dev/null
+++ b/common/host-side/manifest-generator/tests/run_tests.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# Copyright (C) 2015 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.
+
+# Helper script for running unit tests for compatibility libraries
+
+CTS_DIR=$(dirname ${0})/../../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+    compatibility-manifest-generator\
+    compatibility-manifest-generator-tests"
+
+run_tests "com.android.compatibility.common.generator.ManifestGeneratorTest" "${JARS}" "${@}"
+
diff --git a/common/host-side/manifest-generator/tests/src/com/android/compatibility/common/generator/ManifestGeneratorTest.java b/common/host-side/manifest-generator/tests/src/com/android/compatibility/common/generator/ManifestGeneratorTest.java
index 457bbb8..a0565e1 100644
--- a/common/host-side/manifest-generator/tests/src/com/android/compatibility/common/generator/ManifestGeneratorTest.java
+++ b/common/host-side/manifest-generator/tests/src/com/android/compatibility/common/generator/ManifestGeneratorTest.java
@@ -29,10 +29,12 @@
 
     private static final String PACKAGE = "test.package";
     private static final String INSTRUMENT = "test.package.TestInstrument";
+    private static final String MIN_SDK = "8";
+    private static final String TARGET_SDK = "9";
     private static final String MANIFEST = "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>\r\n"
         + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" "
         + "package=\"test.package\">\r\n"
-        + "  <uses-sdk android:minSdkVersion=\"8\" />\r\n"
+        + "  <uses-sdk android:minSdkVersion=\"8\" android:targetSdkVersion=\"9\" />\r\n"
         + "%s"
         + "  <application>\r\n"
         + "%s"
@@ -66,7 +68,8 @@
                 return this.string.toString();
             }
         };
-        ManifestGenerator.generate(output, PACKAGE, INSTRUMENT, permissions, activities);
+        ManifestGenerator.generate(output, PACKAGE, INSTRUMENT, MIN_SDK, TARGET_SDK,
+            permissions, activities);
         String permissionXml = String.format(PERMISSION, PERMISSION_A)
                 + String.format(PERMISSION, PERMISSION_B);
         String activityXml = String.format(ACTIVITY, ACTIVITY_A)
diff --git a/common/host-side/native-scanner/Android.mk b/common/host-side/native-scanner/Android.mk
deleted file mode 100644
index 184cdc0..0000000
--- a/common/host-side/native-scanner/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAR_MANIFEST := MANIFEST.mf
-
-LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
-
-LOCAL_JAVA_LIBRARIES := compatibility-common-util-hostsidelib_v2
-
-LOCAL_MODULE := compatibility-native-scanner_v2
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-################################################################################
-# Build the tests
-###############################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, tests/src)
-
-LOCAL_JAVA_LIBRARIES := compatibility-tradefed_v2 compatibility-native-scanner_v2 junit
-
-LOCAL_MODULE := compatibility-native-scanner-tests_v2
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/native-scanner/MANIFEST.mf b/common/host-side/native-scanner/MANIFEST.mf
deleted file mode 100644
index c5641ca..0000000
--- a/common/host-side/native-scanner/MANIFEST.mf
+++ /dev/null
@@ -1,3 +0,0 @@
-Manifest-Version: 1.0
-Main-Class: com.android.compatibility.common.scanner.NativeScanner
-Class-Path: compatibility-common-util-hostsidelib_v2.jar
diff --git a/common/host-side/native-scanner/src/com/android/compatibility/common/scanner/NativeScanner.java b/common/host-side/native-scanner/src/com/android/compatibility/common/scanner/NativeScanner.java
deleted file mode 100644
index 7b9e447..0000000
--- a/common/host-side/native-scanner/src/com/android/compatibility/common/scanner/NativeScanner.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.compatibility.common.scanner;
-
-import com.android.compatibility.common.util.KeyValueArgsParser;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * Passes the gtest output and outputs a list of test classes and methods.
- */
-public final class NativeScanner {
-
-    private static final String TEST_SUITE_ARG = "t";
-    private static final String USAGE = "Usage: compatibility-native-scanner -t TEST_SUITE"
-        + "  This code reads from stdin the list of tests."
-        + "  The format expected:"
-        + "    TEST_CASE_NAME."
-        + "      TEST_NAME";
-
-    /**
-     * @return An {@link ArrayList} of suites, classes and method names.
-     */
-    static ArrayList<String> getTestNames(BufferedReader reader, String testSuite)
-            throws IOException {
-        ArrayList<String> testNames = new ArrayList<String>();
-        testNames.add("suite:" + testSuite);
-
-        String testCaseName = null;
-        String line;
-        while ((line = reader.readLine()) != null) {
-            if (line.length() == 0) {
-                continue;
-            }
-            if (line.charAt(0) == ' ') {
-                if (testCaseName == null) {
-                    throw new RuntimeException("TEST_CASE_NAME not defined before first test.");
-                }
-                testNames.add("test:" + line.trim());
-            } else {
-                testCaseName = line.trim();
-                if (testCaseName.endsWith(".")) {
-                    testCaseName = testCaseName.substring(0, testCaseName.length()-1);
-                }
-                testNames.add("case:" + testCaseName);
-            }
-        }
-        return testNames;
-    }
-
-    /** Lookup test suite argument and scan {@code System.in} for test cases */
-    public static void main(String[] args) throws IOException {
-        HashMap<String, String> argMap = KeyValueArgsParser.parse(args);
-        if (!argMap.containsKey(TEST_SUITE_ARG)) {
-            System.err.println(USAGE);
-            System.exit(1);
-        }
-
-        String testSuite = argMap.get(TEST_SUITE_ARG);
-
-        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
-        for (String name : getTestNames(reader, testSuite)) {
-            System.out.println(name);
-        }
-    }
-}
diff --git a/common/host-side/native-scanner/tests/src/com/android/compatibility/common/scanner/NativeScannerTest.java b/common/host-side/native-scanner/tests/src/com/android/compatibility/common/scanner/NativeScannerTest.java
deleted file mode 100644
index c5d3157..0000000
--- a/common/host-side/native-scanner/tests/src/com/android/compatibility/common/scanner/NativeScannerTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.compatibility.common.scanner;
-
-import com.android.compatibility.common.scanner.NativeScanner;
-
-import junit.framework.TestCase;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.List;
-import java.util.Iterator;
-
-public class NativeScannerTest extends TestCase {
-
-    public void testSingleTestNamesCase() throws Exception {
-        StringReader singleTestString = new StringReader("FakeTestCase.\n  FakeTestName\n");
-        BufferedReader reader = new BufferedReader(singleTestString);
-
-        List<String> names = NativeScanner.getTestNames(reader, "TestSuite");
-        Iterator<String> it = names.iterator();
-        assertEquals("suite:TestSuite", it.next());
-        assertEquals("case:FakeTestCase", it.next());
-        assertEquals("test:FakeTestName", it.next());
-        assertFalse(it.hasNext());
-    }
-
-    public void testMultipleTestNamesCase() throws Exception {
-        StringReader singleTestString = new StringReader(
-          "Case1.\n  Test1\n  Test2\nCase2.\n  Test3\n Test4\n");
-        BufferedReader reader = new BufferedReader(singleTestString);
-
-        List<String> names = NativeScanner.getTestNames(reader, "TestSuite");
-
-        Iterator<String> it = names.iterator();
-        assertEquals("suite:TestSuite", it.next());
-        assertEquals("case:Case1", it.next());
-        assertEquals("test:Test1", it.next());
-        assertEquals("test:Test2", it.next());
-        assertEquals("case:Case2", it.next());
-        assertEquals("test:Test3", it.next());
-        assertEquals("test:Test4", it.next());
-        assertFalse(it.hasNext());
-    }
-
-    public void testMissingTestCaseNameCase() throws IOException {
-        StringReader singleTestString = new StringReader("  Test1\n");
-        BufferedReader reader = new BufferedReader(singleTestString);
-
-        try {
-            NativeScanner.getTestNames(reader, "TestSuite");
-            fail("Expected RuntimeException");
-        } catch (RuntimeException expected) {}
-    }
-}
diff --git a/common/host-side/scripts/compatibility-tests_v2 b/common/host-side/scripts/compatibility-tests_v2
deleted file mode 100755
index 797909e..0000000
--- a/common/host-side/scripts/compatibility-tests_v2
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-checkFile() {
-    if [ ! -f "$1" ]; then
-        echo "Unable to locate $1"
-        exit
-    fi;
-}
-
-HOST_JAR_DIR=${ANDROID_HOST_OUT}/framework
-HOST_JARS="ddmlib-prebuilt tradefed-prebuilt hosttestlib\
-    compatibility-tradefed_v2 compatibility-tradefed-tests_v2\
-    compatibility-java-scanner_v2 compatibility-java-scanner-tests_v2\
-    compatibility-native-scanner_v2 compatibility-native-scanner-tests_v2\
-    compatibility-xml-plan-generator_v2 compatibility-xml-plan-generator-tests_v2\
-    compatibility-device-util-tests_v2 compatibility-device-setup-tests_v2\
-    compatibility-common-util-hostsidelib_v2 compatibility-common-util-tests_v2"
-
-for JAR in ${HOST_JARS}; do
-    checkFile ${HOST_JAR_DIR}/${JAR}.jar
-    JAR_PATH=${JAR_PATH}:${HOST_JAR_DIR}/${JAR}.jar
-done
-
-DEVICE_LIBS_DIR=${ANDROID_PRODUCT_OUT}/obj/JAVA_LIBRARIES
-DEVICE_LIBS="compatibility-common-util-devicesidelib_v2 compatibility-device-util_v2\
-    compatibility-device-setup_v2"
-
-for LIB in ${DEVICE_LIBS}; do
-    checkFile ${DEVICE_LIBS_DIR}/${LIB}_intermediates/javalib.jar
-    JAR_PATH=${JAR_PATH}:${DEVICE_LIBS_DIR}/${LIB}_intermediates/javalib.jar
-done
-
-# TODO(stuartscott): Currently the test classes are explicitly set here, but
-# once our wrappers for tradefed are in place we can make it scan and generate
-# the list of test at runtime.
-TEST_CLASSES="com.android.compatibility.common.devicesetup.DeviceSetupTest\
-    com.android.compatibility.common.scanner.JavaScannerTest\
-    com.android.compatibility.common.scanner.NativeScannerTest\
-    com.android.compatibility.common.tradefed.TradefedTest\
-    com.android.compatibility.common.util.DeviceUtilTest\
-    com.android.compatibility.common.util.CommonUtilTest\
-    com.android.compatibility.common.xmlgenerator.XmlPlanGeneratorTest"
-
-for CLASS in ${TEST_CLASSES}; do
-    java $RDBG_FLAG -cp ${JAR_PATH} com.android.compatibility.common.tradefed.command.CompatibilityConsole run\
-            singleCommand host -n --class ${CLASS} "$@"
-done
diff --git a/common/host-side/scripts/compatibility-tradefed_v2 b/common/host-side/scripts/compatibility-tradefed_v2
deleted file mode 100755
index f64e273..0000000
--- a/common/host-side/scripts/compatibility-tradefed_v2
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-#
-# 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.
-echo "TODO(stuartscott): Add the wrapper to launch the executable. This will be done in the next CL"
diff --git a/common/host-side/tradefed/Android.mk b/common/host-side/tradefed/Android.mk
index 8ff7c8c..3ed225ed 100644
--- a/common/host-side/tradefed/Android.mk
+++ b/common/host-side/tradefed/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 The Android Open Source Project
+# Copyright (C) 2015 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.
@@ -12,40 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-###############################################################################
-# Builds the compatibility tradefed host library
-###############################################################################
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-#LOCAL_JAVA_RESOURCE_DIRS := res
-
-LOCAL_MODULE := compatibility-tradefed_v2
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt hosttestlib compatibility-common-util-hostsidelib_v2
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-###############################################################################
-# Build the compatibility tradefed tests
-###############################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, tests/src)
-
-LOCAL_MODULE := compatibility-tradefed-tests_v2
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt compatibility-tradefed_v2 junit
-
-LOCAL_STATIC_JAVA_LIBRARIES := easymock
-
-include $(BUILD_HOST_JAVA_LIBRARY)
+include $(call all-subdir-makefiles)
\ No newline at end of file
diff --git a/common/host-side/tradefed/res/config/common-compatibility-config.xml b/common/host-side/tradefed/res/config/common-compatibility-config.xml
new file mode 100644
index 0000000..5bac748
--- /dev/null
+++ b/common/host-side/tradefed/res/config/common-compatibility-config.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Common config for Compatibility suites">
+
+    <device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
+    <build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
+    <test class="com.android.compatibility.common.tradefed.testtype.CompatibilityTest" />
+    <logger class="com.android.tradefed.log.FileLogger" />
+    <result_reporter class="com.android.compatibility.common.tradefed.result.ResultReporter" />
+
+</configuration>
diff --git a/common/host-side/tradefed/res/config/everything.xml b/common/host-side/tradefed/res/config/everything.xml
new file mode 100644
index 0000000..d1ac900
--- /dev/null
+++ b/common/host-side/tradefed/res/config/everything.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Common config for Compatibility suites to run all modules">
+
+    <include name="common-compatibility-config" />
+    <option name="compatibility:plan" value="everything" />
+
+</configuration>
diff --git a/common/host-side/tradefed/res/report/compatibility_result.css b/common/host-side/tradefed/res/report/compatibility_result.css
new file mode 100644
index 0000000..699f45a
--- /dev/null
+++ b/common/host-side/tradefed/res/report/compatibility_result.css
@@ -0,0 +1,164 @@
+/* Copyright (C) 2015 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.
+*/
+
+body {
+    font-family:arial,sans-serif;
+    color:#000;
+    font-size:13px;
+    color:#333;
+    padding:10;
+    margin:10;
+}
+
+/* Report logo and device name */
+table.title {
+    padding:5px;
+    border-width: 0px;
+    margin-left:auto;
+    margin-right:auto;
+    vertical-align:middle;
+}
+
+table.summary {
+    background-color: rgb(212, 233, 169);
+    border-collapse:collapse;
+    border: 0px solid #A5C639;
+    margin-left:auto;
+    margin-right:auto;
+}
+
+table.summary th {
+    background-color: #A5C639;
+    font-size: 1.2em;
+    padding: 0.5em;
+}
+
+table.summary td {
+    border-width: 0px 0px 0px 0px;
+    border-color: gray;
+    border-style: inset;
+    font-size: 1em;
+    padding: 0.5em;
+    vertical-align: top;
+}
+
+table.testsummary {
+    background-color: rgb(212, 233, 169);
+    border-collapse:collapse;
+    margin-left:auto;
+    margin-right:auto;
+}
+
+table.testsummary th {
+    background-color: #A5C639;
+    border: 1px outset gray;
+    padding: 0.5em;
+}
+
+table.testsummary td {
+    border: 1px outset #A5C639;
+    padding: 0.5em;
+    text-align: center;
+}
+
+table.testdetails {
+    background-color: rgb(212, 233, 169);
+    border-collapse:collapse;
+    border-width:1;
+    border-color: #A5C639;
+    margin-left:auto;
+    margin-right:auto;
+    margin-bottom: 2em;
+    vertical-align: top;
+    width: 95%;
+}
+
+table.testdetails th {
+    background-color: #A5C639;
+    border-width: 1px;
+    border-color: gray;
+    border-style: outset;
+    height: 2em;
+    padding: 0.2em;
+}
+
+table.testdetails td {
+    border-width: 1px;
+    border-color: #A5C639;
+    border-style: outset;
+    text-align: left;
+    vertical-align: top;
+    padding: 0.2em;
+}
+
+table.testdetails td.module {
+    background-color: white;
+    border: 0px;
+    font-weight: bold;
+}
+
+/* Test cell details */
+td.failed {
+    background-color: #FA5858;
+    font-weight:bold;
+    vertical-align: top;
+    text-align: center;
+}
+
+td.failuredetails {
+    text-align: left;
+}
+
+td.pass {
+    text-align: center;
+    margin-left:auto;
+    margin-right:auto;
+}
+
+td.not_executed {
+    background-color: #A5C639;
+    vertical-align: top;
+    text-align: center;
+}
+
+td.testname {
+    border-width: 1px;
+    border-color: #A5C639;
+    border-style: outset;
+    text-align: left;
+    vertical-align: top;
+    padding:1;
+    overflow:hidden;
+}
+
+td.testcase {
+    border-width: 1px;
+    border-color: #A5C639;
+    border-style: outset;
+    text-align: left;
+    vertical-align: top;
+    padding:1;
+    overflow:hidden;
+    font-weight:bold;
+}
+
+div.details {
+    white-space: pre-wrap;       /* css-3 */
+    white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
+    white-space: -pre-wrap;      /* Opera 4-6 */
+    white-space: -o-pre-wrap;    /* Opera 7 */
+    word-wrap: break-word;       /* Internet Explorer 5.5+ */
+    overflow:auto;
+}
diff --git a/common/host-side/tradefed/res/report/compatibility_result.xsd b/common/host-side/tradefed/res/report/compatibility_result.xsd
new file mode 100644
index 0000000..9b2758c
--- /dev/null
+++ b/common/host-side/tradefed/res/report/compatibility_result.xsd
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           targetNamespace="http://compatibility.android.com/compatibility_result/1.15"
+           xmlns="http://compatibility.android.com/compatibility_result/1.15"
+           elementFormDefault="qualified">
+
+  <xs:element name="Result">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="Summary" type="summaryType"/>
+        <xs:element name="Module" type="moduleType" minOccurs="1" maxOccurs="unbounded"/>
+      </xs:sequence>
+      <xs:attribute name="start" type="xs:string"/>
+      <xs:attribute name="end" type="xs:string"/>
+      <xs:attribute name="plan" type="xs:string"/>
+      <xs:attribute name="suite_name" type="xs:string"/>
+      <xs:attribute name="suite_version" type="xs:string"/>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:complexType name="summaryType">
+    <xs:attribute name="failed" type="xs:integer"/>
+    <xs:attribute name="not_executed" type="xs:integer"/>
+    <xs:attribute name="pass" type="xs:integer"/>
+  </xs:complexType>
+
+  <xs:complexType name="moduleType">
+    <xs:sequence>
+      <xs:element name="Test" type="testType" minOccurs="1" maxOccurs="unbounded" />
+    </xs:sequence>
+    <xs:attribute name="name" type="xs:string" use="required"/>
+    <xs:attribute name="abi" type="xs:string"/>
+  </xs:complexType>
+
+  <xs:simpleType name="unitType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="none"/>
+      <xs:enumeration value="ms"/>
+      <xs:enumeration value="fps"/>
+      <xs:enumeration value="ops"/>
+      <xs:enumeration value="kbps"/>
+      <xs:enumeration value="mbps"/>
+      <xs:enumeration value="byte"/>
+      <xs:enumeration value="count"/>
+      <xs:enumeration value="score"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="scoreTypeType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="higher-better"/>
+      <xs:enumeration value="lower-better"/>
+      <xs:enumeration value="neutral"/>
+      <xs:enumeration value="warning"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:complexType name="testType">
+    <xs:sequence>
+      <xs:element name="Failure" minOccurs="0" maxOccurs="1">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="StackTrace" type="xs:string" minOccurs="0" maxOccurs="1"/>
+          </xs:sequence>
+          <xs:attribute name="message" type="xs:string"/>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="Summary" minOccurs="0" maxOccurs="1">
+        <xs:complexType>
+          <xs:simpleContent>
+            <xs:extension base="xs:decimal">
+              <xs:attribute name="message" type="xs:string" use="required" />
+              <xs:attribute name="scoreType" type="scoreTypeType" use="required" />
+              <xs:attribute name="unit" type="unitType" use="required" />
+              <xs:attribute name="target" type="xs:decimal" />
+            </xs:extension>
+          </xs:simpleContent>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="Details" minOccurs="0" maxOccurs="1">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="ValueArray" minOccurs="0" maxOccurs="unbounded">
+              <xs:complexType>
+                <xs:sequence>
+                  <xs:element name="Value" type="xs:decimal" minOccurs="0" maxOccurs="unbounded" />
+                </xs:sequence>
+                <xs:attribute name="source" type="xs:string" use="required" />
+                <xs:attribute name="message" type="xs:string" use="required" />
+                <xs:attribute name="scoreType" type="scoreTypeType" use="required" />
+                <xs:attribute name="unit" type="unitType" use="required" />
+              </xs:complexType>
+            </xs:element>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+    <xs:attribute name="name" type="xs:string" use="required"/>
+    <xs:attribute name="result" type="resultType" use="required"/>
+    <xs:attribute name="start" type="xs:string"/>
+    <xs:attribute name="end" type="xs:string"/>
+  </xs:complexType>
+
+  <xs:simpleType name="resultType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="pass"/>
+      <xs:enumeration value="fail"/>
+      <xs:enumeration value="not_executed"/>
+    </xs:restriction>
+  </xs:simpleType>
+</xs:schema>
\ No newline at end of file
diff --git a/common/host-side/tradefed/res/report/compatibility_result.xsl b/common/host-side/tradefed/res/report/compatibility_result.xsl
new file mode 100644
index 0000000..1fb4e83
--- /dev/null
+++ b/common/host-side/tradefed/res/report/compatibility_result.xsl
@@ -0,0 +1,273 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#160;"> ]>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+    <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
+
+    <xsl:template match="/">
+
+        <html>
+            <head>
+                <title>Test Report</title>
+                <style type="text/css">
+                    @import "compatibility_result.css";
+                </style>
+            </head>
+            <body>
+                <div>
+                    <table class="title">
+                        <tr>
+                            <td width="40%" align="left"><img src="logo.png"></img></td>
+                            <td width="60%" align="left">
+                                <h1>Test Report</h1>
+                            </td>
+                        </tr>
+                    </table>
+                </div>
+                <img src="newrule_green.png" align="left"></img>
+
+                <br></br>
+
+                <center>
+                    <a href="device-info/GenericDeviceInfo.deviceinfo.json" >Device Information</a>
+                </center>
+
+                <br></br>
+
+                <div>
+                    <table class="summary">
+                        <tr>
+                            <th colspan="2">Test Summary</th>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Compatibility Suite</td>
+                            <td>
+                                <xsl:value-of select="Result/@suite_name"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Compatibility Version</td>
+                            <td>
+                                <xsl:value-of select="Result/@suite_version"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Report Version</td>
+                            <td>
+                                <xsl:value-of select="Result/@report_version"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Host Info</td>
+                            <td>
+                                <xsl:value-of select="Result/@host_name"/>
+                                (<xsl:value-of select="Result/@os_name"/> - <xsl:value-of select="Result/@os_version"/>)
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Plan</td>
+                            <td>
+                                <xsl:value-of select="Result/@plan"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Start time</td>
+                            <td>
+                                <xsl:value-of select="Result/@start"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">End time</td>
+                            <td>
+                                <xsl:value-of select="Result/@end"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Tests Passed</td>
+                            <td>
+                                <xsl:value-of select="Result/Summary/@pass"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Tests Failed</td>
+                            <td>
+                                <xsl:value-of select="Result/Summary/@failed"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Tests Not Executed</td>
+                            <td>
+                                <xsl:value-of select="Result/Summary/@not_executed"/>
+                            </td>
+                        </tr>
+                    </table>
+                </div>
+
+                <!-- High level summary of test execution -->
+                <h2 align="center">Test Summary by Module</h2>
+                <div>
+                    <table class="testsummary">
+                        <tr>
+                            <th>Module</th>
+                            <th>Passed</th>
+                            <th>Failed</th>
+                            <th>Not Executed</th>
+                            <th>Total Tests</th>
+                        </tr>
+                        <xsl:for-each select="Result/Module">
+                            <tr>
+                                <td>
+                                    <xsl:variable name="href"><xsl:value-of select="@name"/> - <xsl:value-of select="@abi"/></xsl:variable>
+                                    <a href="#{$href}"><xsl:value-of select="@name"/> - <xsl:value-of select="@abi"/></a>
+                                </td>
+                                <td>
+                                    <xsl:value-of select="count(Test[@result = 'pass'])"/>
+                                </td>
+                                <td>
+                                    <xsl:value-of select="count(Test[@result = 'fail'])"/>
+                                </td>
+                                <td>
+                                    <xsl:value-of select="count(Test[@result = 'not_executed'])"/>
+                                </td>
+                                <td>
+                                    <xsl:value-of select="count(Test)"/>
+                                </td>
+                            </tr>
+                        </xsl:for-each> <!-- end Module -->
+                    </table>
+                </div>
+
+                <xsl:call-template name="filteredResultTestReport">
+                    <xsl:with-param name="header" select="'Failured Tests'" />
+                    <xsl:with-param name="resultFilter" select="'fail'" />
+                </xsl:call-template>
+
+                <xsl:call-template name="filteredResultTestReport">
+                    <xsl:with-param name="header" select="'Not Executed Tests'" />
+                    <xsl:with-param name="resultFilter" select="'not_executed'" />
+                </xsl:call-template>
+
+                <h2 align="center">Detailed Test Report</h2>
+                <xsl:call-template name="detailedTestReport" />
+
+            </body>
+        </html>
+    </xsl:template>
+
+    <xsl:template name="filteredResultTestReport">
+        <xsl:param name="header" />
+        <xsl:param name="resultFilter" />
+        <xsl:variable name="numMatching" select="count(Result/Module/Test[@result=$resultFilter])" />
+        <xsl:if test="$numMatching &gt; 0">
+            <h2 align="center"><xsl:value-of select="$header" /> (<xsl:value-of select="$numMatching"/>)</h2>
+            <xsl:call-template name="detailedTestReport">
+                <xsl:with-param name="resultFilter" select="$resultFilter"/>
+            </xsl:call-template>
+        </xsl:if>
+    </xsl:template>
+
+    <xsl:template name="detailedTestReport">
+        <xsl:param name="resultFilter" />
+        <div>
+            <xsl:for-each select="Result/Module">
+                <xsl:if test="$resultFilter=''
+                        or count(Test[@result=$resultFilter]) &gt; 0">
+
+                    <table class="testdetails">
+                        <tr>
+                            <td class="module" colspan="3">
+                                <xsl:variable name="href"><xsl:value-of select="@name"/> - <xsl:value-of select="@abi"/></xsl:variable>
+                                <a name="{$href}"><xsl:value-of select="@name"/> - <xsl:value-of select="@abi"/></a>
+                            </td>
+                        </tr>
+
+                        <tr>
+                            <th width="30%">Test</th>
+                            <th width="5%">Result</th>
+                            <th>Details</th>
+                        </tr>
+
+                        <!-- test -->
+                        <xsl:for-each select="Test">
+                            <xsl:if test="$resultFilter='' or $resultFilter=@result">
+                                <tr>
+                                    <td class="testname"> -- <xsl:value-of select="@name"/></td>
+
+                                    <!-- test results -->
+                                    <xsl:if test="@result='pass'">
+                                        <td class="pass">
+                                            <div style="text-align: center; margin-left:auto; margin-right:auto;">
+                                                <xsl:value-of select="@result"/>
+                                            </div>
+                                        </td>
+                                        <td class="failuredetails"/>
+                                    </xsl:if>
+
+                                    <xsl:if test="@result='fail'">
+                                        <td class="failed">
+                                            <div style="text-align: center; margin-left:auto; margin-right:auto;">
+                                                <xsl:value-of select="@result"/>
+                                            </div>
+                                        </td>
+                                        <td class="failuredetails">
+                                            <div class="details">
+                                                <xsl:value-of select="Failure/@message"/>
+                                            </div>
+                                        </td>
+                                    </xsl:if>
+
+                                    <xsl:if test="@result='not_executed'">
+                                        <td class="not_executed">
+                                            <div style="text-align: center; margin-left:auto; margin-right:auto;">
+                                                <xsl:value-of select="@result"/>
+                                            </div>
+                                        </td>
+                                        <td class="failuredetails"></td>
+                                    </xsl:if>
+                                </tr> <!-- finished with a row -->
+                            </xsl:if>
+                        </xsl:for-each> <!-- end test -->
+                    </table>
+                </xsl:if>
+            </xsl:for-each> <!-- end test Module -->
+        </div>
+    </xsl:template>
+
+    <!-- Take a delimited string and insert line breaks after a some number of elements. -->
+    <xsl:template name="formatDelimitedString">
+        <xsl:param name="string" />
+        <xsl:param name="numTokensPerRow" select="10" />
+        <xsl:param name="tokenIndex" select="1" />
+        <xsl:if test="$string">
+            <!-- Requires the last element to also have a delimiter after it. -->
+            <xsl:variable name="token" select="substring-before($string, ';')" />
+            <xsl:value-of select="$token" />
+            <xsl:text>&#160;</xsl:text>
+
+            <xsl:if test="$tokenIndex mod $numTokensPerRow = 0">
+                <br />
+            </xsl:if>
+
+            <xsl:call-template name="formatDelimitedString">
+                <xsl:with-param name="string" select="substring-after($string, ';')" />
+                <xsl:with-param name="numTokensPerRow" select="$numTokensPerRow" />
+                <xsl:with-param name="tokenIndex" select="$tokenIndex + 1" />
+            </xsl:call-template>
+        </xsl:if>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/common/host-side/tradefed/res/report/logo.png b/common/host-side/tradefed/res/report/logo.png
new file mode 100644
index 0000000..61970b3
--- /dev/null
+++ b/common/host-side/tradefed/res/report/logo.png
Binary files differ
diff --git a/common/host-side/tradefed/res/report/newrule_green.png b/common/host-side/tradefed/res/report/newrule_green.png
new file mode 100644
index 0000000..10a4194
--- /dev/null
+++ b/common/host-side/tradefed/res/report/newrule_green.png
Binary files differ
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
new file mode 100644
index 0000000..f2ce00b
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.build;
+
+import com.android.compatibility.SuiteInfo;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.build.IFolderBuildInfo;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A simple helper that stores and retrieves information from a {@link IBuildInfo}.
+ */
+public class CompatibilityBuildHelper {
+
+    private static final String ROOT_DIR = "ROOT_DIR";
+    private static final String SUITE_BUILD = "SUITE_BUILD";
+    private static final String SUITE_NAME = "SUITE_NAME";
+    private static final String SUITE_FULL_NAME = "SUITE_FULL_NAME";
+    private static final String SUITE_VERSION = "SUITE_VERSION";
+    private static final String SUITE_PLAN = "SUITE_PLAN";
+    private static final String RESULT_DIR = "RESULT_DIR";
+    private static final String CONFIG_PATH_PREFIX = "DYNAMIC_CONFIG_FILE:";
+    private static final String DYNAMIC_CONFIG_OVERRIDE_URL = "DYNAMIC_CONFIG_OVERRIDE_URL";
+    private final IBuildInfo mBuildInfo;
+    private boolean mInitialized = false;
+
+    /**
+     * Creates a {@link CompatibilityBuildHelper} wrapping the given {@link IBuildInfo}.
+     */
+    public CompatibilityBuildHelper(IBuildInfo buildInfo) {
+        mBuildInfo = buildInfo;
+    }
+
+    /**
+     * Initializes the {@link IBuildInfo} from the manifest.
+     */
+    public void init(String suitePlan, String dynamicConfigUrl) {
+        if (mInitialized) {
+            return;
+        }
+        mInitialized = true;
+        mBuildInfo.addBuildAttribute(SUITE_BUILD, SuiteInfo.BUILD_NUMBER);
+        mBuildInfo.addBuildAttribute(SUITE_NAME, SuiteInfo.NAME);
+        mBuildInfo.addBuildAttribute(SUITE_FULL_NAME, SuiteInfo.FULLNAME);
+        mBuildInfo.addBuildAttribute(SUITE_VERSION, SuiteInfo.VERSION);
+        mBuildInfo.addBuildAttribute(SUITE_PLAN, suitePlan);
+        String rootDirPath = null;
+        if (mBuildInfo instanceof IFolderBuildInfo) {
+            File rootDir = ((IFolderBuildInfo) mBuildInfo).getRootDir();
+            if (rootDir != null) {
+                rootDirPath = rootDir.getAbsolutePath();
+            }
+        }
+        rootDirPath = System.getProperty(String.format("%s_ROOT", SuiteInfo.NAME), rootDirPath);
+        if (rootDirPath == null || rootDirPath.trim().equals("")) {
+            throw new IllegalArgumentException(
+                    String.format("Missing install path property %s_ROOT", SuiteInfo.NAME));
+        }
+        File rootDir = new File(rootDirPath);
+        if (!rootDir.exists()) {
+            throw new IllegalArgumentException(
+                    String.format("Root directory doesn't exist %s", rootDir.getAbsolutePath()));
+        }
+        mBuildInfo.addBuildAttribute(ROOT_DIR, rootDir.getAbsolutePath());
+        if (dynamicConfigUrl != null && !dynamicConfigUrl.isEmpty()) {
+            mBuildInfo.addBuildAttribute(DYNAMIC_CONFIG_OVERRIDE_URL,
+                    dynamicConfigUrl.replace("{suite-name}", getSuiteName()));
+        }
+    }
+
+    public String getSuiteBuild() {
+        return mBuildInfo.getBuildAttributes().get(SUITE_BUILD);
+    }
+
+    public String getSuiteName() {
+        return mBuildInfo.getBuildAttributes().get(SUITE_NAME);
+    }
+
+    public String getSuiteFullName() {
+        return mBuildInfo.getBuildAttributes().get(SUITE_FULL_NAME);
+    }
+
+    public String getSuiteVersion() {
+        return mBuildInfo.getBuildAttributes().get(SUITE_VERSION);
+    }
+
+    public String getSuitePlan() {
+        return mBuildInfo.getBuildAttributes().get(SUITE_PLAN);
+    }
+
+    public String getDynamicConfigUrl() {
+        return mBuildInfo.getBuildAttributes().get(DYNAMIC_CONFIG_OVERRIDE_URL);
+    }
+
+    public void addDynamicConfigFile(String moduleName, File configFile) {
+        mBuildInfo.addBuildAttribute(CONFIG_PATH_PREFIX + moduleName, configFile.getAbsolutePath());
+    }
+
+    public Map<String, File> getDynamicConfigFiles() {
+        Map<String, File> configMap = new HashMap<>();
+        for (String key : mBuildInfo.getBuildAttributes().keySet()) {
+            if (key.startsWith(CONFIG_PATH_PREFIX)) {
+                configMap.put(key.substring(CONFIG_PATH_PREFIX.length()),
+                        new File(mBuildInfo.getBuildAttributes().get(key)));
+            }
+        }
+        return configMap;
+    }
+
+    /**
+     * @return a {@link File} representing the directory holding the Compatibility installation
+     * @throws FileNotFoundException if the directory does not exist
+     */
+    public File getRootDir() throws FileNotFoundException {
+        File dir = new File(mBuildInfo.getBuildAttributes().get(ROOT_DIR));
+        if (!dir.exists()) {
+            throw new FileNotFoundException(String.format(
+                    "Compatibility root directory %s does not exist",
+                    dir.getAbsolutePath()));
+        }
+        return dir;
+    }
+
+    /**
+     * @return a {@link File} representing the "android-<suite>" folder of the Compatibility
+     * installation
+     * @throws FileNotFoundException if the directory does not exist
+     */
+    public File getDir() throws FileNotFoundException {
+        File dir = new File(getRootDir(), String.format("android-%s", getSuiteName().toLowerCase()));
+        if (!dir.exists()) {
+            throw new FileNotFoundException(String.format(
+                    "Compatibility install folder %s does not exist",
+                    dir.getAbsolutePath()));
+        }
+        return dir;
+    }
+
+    /**
+     * @return a {@link File} representing the results directory.
+     * @throws FileNotFoundException if the directory structure is not valid.
+     */
+    public File getResultsDir() throws FileNotFoundException {
+        return new File(getDir(), "results");
+    }
+
+    /**
+     * Sets the name of the current invocation's result directory.
+     */
+    public void setResultDir(String resultDir) {
+        mBuildInfo.addBuildAttribute(RESULT_DIR, resultDir);
+    }
+
+    /**
+     * @return a {@link File} representing the result directory of the current invocation.
+     * @throws FileNotFoundException if the directory structure is not valid.
+     */
+    public File getResultDir() throws FileNotFoundException {
+        return new File(getResultsDir(), mBuildInfo.getBuildAttributes().get(RESULT_DIR));
+    }
+
+    /**
+     * @return a {@link File} representing the directory to store result logs.
+     * @throws FileNotFoundException if the directory structure is not valid.
+     */
+    public File getLogsDir() throws FileNotFoundException {
+        return new File(getDir(), "logs");
+    }
+
+    /**
+     * @return a {@link File} representing the test modules directory.
+     * @throws FileNotFoundException if the directory structure is not valid.
+     */
+    public File getTestsDir() throws FileNotFoundException {
+        File testsDir = new File(getDir(), "testcases");
+        if (!testsDir.exists()) {
+            throw new FileNotFoundException(String.format(
+                    "Compatibility tests folder %s does not exist",
+                    testsDir.getAbsolutePath()));
+        }
+        return testsDir;
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
new file mode 100644
index 0000000..65f60bd
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.build;
+
+import com.android.tradefed.build.BuildInfo;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.build.IBuildProvider;
+import com.android.tradefed.config.OptionClass;
+
+/**
+ * A simple {@link IBuildProvider} that uses a pre-existing Compatibility install.
+ */
+@OptionClass(alias="compatibility-build-provider")
+public class CompatibilityBuildProvider implements IBuildProvider {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IBuildInfo getBuild() {
+        // Create a blank BuildInfo which will get populated later.
+        return new BuildInfo();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void buildNotTested(IBuildInfo info) {
+        // ignore
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void cleanUp(IBuildInfo info) {
+        // ignore
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
index dfd1c71..db4ac73 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -13,19 +13,213 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.android.compatibility.common.tradefed.command;
 
+import com.android.compatibility.SuiteInfo;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
+import com.android.compatibility.common.tradefed.result.IInvocationResultRepo;
+import com.android.compatibility.common.tradefed.result.InvocationResultRepo;
+import com.android.compatibility.common.tradefed.testtype.ModuleRepo;
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.TestStatus;
 import com.android.tradefed.command.Console;
 import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.util.ArrayUtil;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.RegexTrie;
+import com.android.tradefed.util.TableFormatter;
+import com.android.tradefed.util.TimeUtil;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 
 /**
  * An extension of Tradefed's console which adds features specific to compatibility testing.
  */
 public class CompatibilityConsole extends Console {
 
+    private CompatibilityBuildHelper mBuildHelper;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void run() {
+        printLine(String.format("Android %s %s (%s)", SuiteInfo.FULLNAME, SuiteInfo.VERSION,
+                SuiteInfo.BUILD_NUMBER));
+        super.run();
+    }
+
+    /**
+     * Adds the 'list plans', 'list modules' and 'list results' commands
+     */
+    @Override
+    protected void setCustomCommands(RegexTrie<Runnable> trie, List<String> genericHelp,
+            Map<String, String> commandHelp) {
+        trie.put(new Runnable() {
+            @Override
+            public void run() {
+                // TODO(stuartscott)" listPlans(buildHelper);
+            }
+        }, LIST_PATTERN, "p(?:lans)?");
+        trie.put(new Runnable() {
+            @Override
+            public void run() {
+                listModules();
+            }
+        }, LIST_PATTERN, "m(?:odules)?");
+        trie.put(new Runnable() {
+            @Override
+            public void run() {
+                listResults();
+            }
+        }, LIST_PATTERN, "r(?:esults)?");
+
+        // find existing help for 'LIST_PATTERN' commands, and append these commands help
+        String listHelp = commandHelp.get(LIST_PATTERN);
+        if (listHelp == null) {
+            // no help? Unexpected, but soldier on
+            listHelp = new String();
+        }
+        String combinedHelp = listHelp +
+                "\tp[lans]\tList all plans" + LINE_SEPARATOR +
+                "\tm[odules]\tList all modules" + LINE_SEPARATOR +
+                "\tr[esults]\tList all results" + LINE_SEPARATOR;
+        commandHelp.put(LIST_PATTERN, combinedHelp);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected String getConsolePrompt() {
+        return String.format("%s-tf > ", SuiteInfo.NAME.toLowerCase());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected String getGenericHelpString(List<String> genericHelp) {
+        StringBuilder helpBuilder = new StringBuilder();
+        helpBuilder.append(SuiteInfo.FULLNAME);
+        helpBuilder.append("\n\n");
+        helpBuilder.append(SuiteInfo.NAME);
+        helpBuilder.append(" is the test harness for running the Android Compatibility Suite, ");
+        helpBuilder.append("built on top of Trade Federation.\n\n");
+        helpBuilder.append("Available commands and options\n");
+        helpBuilder.append("Host:\n");
+        helpBuilder.append("  help: show this message.\n");
+        helpBuilder.append("  help all: show the complete tradefed help.\n");
+        helpBuilder.append("  version: show the version.\n");
+        helpBuilder.append("  exit: gracefully exit the compatibiltiy console, waiting until all ");
+        helpBuilder.append("invocations have completed.\n");
+        helpBuilder.append("Run:\n");
+        final String runPrompt = "  run <plan> ";
+        helpBuilder.append(runPrompt);
+        helpBuilder.append("--module/-m <module>: run a test module.\n");
+        helpBuilder.append(runPrompt);
+        helpBuilder.append("--module/-m <module> --test/-t <test_name>: run a specific test from");
+        helpBuilder.append(" the module. Test name can be <package>.<class>, ");
+        helpBuilder.append("<package>.<class>#<method> or <native_name>.\n");
+        helpBuilder.append(runPrompt);
+        helpBuilder.append("--retry <session_id>: run all failed tests from a previous session.\n");
+        helpBuilder.append(runPrompt);
+        helpBuilder.append("--help/--help-all: get help for ");
+        helpBuilder.append(SuiteInfo.FULLNAME);
+        helpBuilder.append(".\n");
+        helpBuilder.append("Options:\n");
+        helpBuilder.append("  --serial/-s <device_id>: The device to run the test on.\n");
+        helpBuilder.append("  --abi/-a <abi>: The ABI to run the test against.\n");
+        helpBuilder.append("  --shard <shards>: Shards a run into the given number of independant");
+        helpBuilder.append(" chunks, to run on multiple devices in parallel.\n");
+        helpBuilder.append("  --logcat-on-failure: Capture logcat when a test fails.\n");
+        helpBuilder.append("  --bugreport-on-failure: Capture a bugreport when a test fails.\n");
+        helpBuilder.append("  --screenshot-on-failure: Capture a screenshot when a test fails.\n");
+        helpBuilder.append("List:\n");
+        helpBuilder.append("  l/list d/devices: list connected devices and their state\n");
+        helpBuilder.append("  l/list m/modules: list test modules\n");
+        helpBuilder.append("  l/list i/invocations: list invocations aka test runs currently in ");
+        helpBuilder.append("progress\n");
+        helpBuilder.append("  l/list c/commands: list commands aka test run commands currently");
+        helpBuilder.append(" in the queue waiting to be allocated devices\n");
+        helpBuilder.append("  l/list r/results: list results currently in the repository\n");
+        helpBuilder.append("Dump:\n");
+        helpBuilder.append("  d/dump l/logs: dump the tradefed logs for all running invocations\n");
+        return helpBuilder.toString();
+    }
+
+    private void listModules() {
+        File[] files = null;
+        try {
+            files = getBuildHelper().getTestsDir().listFiles(new ModuleRepo.ConfigFilter());
+        } catch (FileNotFoundException e) {
+            printLine(e.getMessage());
+            e.printStackTrace();
+        }
+        if (files != null && files.length > 0) {
+            List<String> modules = new ArrayList<>();
+            for (File moduleFile : files) {
+                modules.add(FileUtil.getBaseName(moduleFile.getName()));
+            }
+            Collections.sort(modules);
+            for (String module : modules) {
+                printLine(module);
+            }
+        } else {
+            printLine("No modules found");
+        }
+    }
+
+    private void listResults() {
+        TableFormatter tableFormatter = new TableFormatter();
+        List<List<String>> table = new ArrayList<>();
+        table.add(Arrays.asList("Session","Pass", "Fail", "Not Executed", "Start Time", "Test Plan",
+                "Device serial(s)"));
+        IInvocationResultRepo testResultRepo = null;
+        List<IInvocationResult> results = null;
+        try {
+            testResultRepo = new InvocationResultRepo(getBuildHelper().getResultsDir());
+            results = testResultRepo.getResults();
+        } catch (FileNotFoundException e) {
+            printLine(e.getMessage());
+            e.printStackTrace();
+        }
+        if (testResultRepo != null && results.size() > 0) {
+            for (int i = 0; i < results.size(); i++) {
+                IInvocationResult result = results.get(i);
+                table.add(Arrays.asList(Integer.toString(i),
+                        Integer.toString(result.countResults(TestStatus.PASS)),
+                        Integer.toString(result.countResults(TestStatus.FAIL)),
+                        Integer.toString(result.countResults(TestStatus.NOT_EXECUTED)),
+                        TimeUtil.formatTimeStamp(result.getStartTime()),
+                        result.getTestPlan(),
+                        ArrayUtil.join(", ", result.getDeviceSerials())));
+            }
+            tableFormatter.displayTable(table, new PrintWriter(System.out, true));
+        } else {
+            printLine(String.format("No results found"));
+        }
+    }
+
+    private CompatibilityBuildHelper getBuildHelper() {
+        if (mBuildHelper == null) {
+            CompatibilityBuildProvider buildProvider = new CompatibilityBuildProvider();
+            mBuildHelper = new CompatibilityBuildHelper(buildProvider.getBuild());
+            mBuildHelper.init("" /* suite plan */, "" /* dynamic config url */);
+        }
+        return mBuildHelper;
+    }
+
     public static void main(String[] args) throws InterruptedException, ConfigurationException {
-        CompatibilityConsole console = new CompatibilityConsole();
+        Console console = new CompatibilityConsole();
         Console.startConsole(console, args);
     }
 }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/IInvocationResultRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/IInvocationResultRepo.java
new file mode 100644
index 0000000..c07223b0
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/IInvocationResultRepo.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.result;
+
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.InvocationResult;
+
+import java.util.List;
+
+/**
+ * Repository for Compatibility results.
+ */
+public interface IInvocationResultRepo {
+
+    /**
+     * @return the list of {@link IInvocationResult}s. The index is its session id
+     */
+    List<IInvocationResult> getResults();
+
+    /**
+     * Get the {@link IInvocationResult} for given session id.
+     *
+     * @param sessionId the session id
+     * @return the {@link InvocationResult} or <code>null</null> if the result with that session id
+     * cannot be retrieved
+     */
+    IInvocationResult getResult(int sessionId);
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/IModuleListener.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/IModuleListener.java
new file mode 100644
index 0000000..213d293
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/IModuleListener.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.result;
+
+import com.android.tradefed.result.ITestInvocationListener;
+
+/**
+ * Listener for Compatibility tests.
+ * <p>
+ * This listener wraps around the normal listener to convert from module name to module id.
+ */
+public interface IModuleListener extends ITestInvocationListener {
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/InvocationResultRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/InvocationResultRepo.java
new file mode 100644
index 0000000..e046e12
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/InvocationResultRepo.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.result;
+
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.ResultHandler;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An implementation of {@link IInvocationResultRepo}.
+ */
+public class InvocationResultRepo implements IInvocationResultRepo {
+
+    /**
+     * Ordered list of result directories. the index of each file is its session id.
+     */
+    private List<IInvocationResult> mResults;
+
+    /**
+     * Create a {@link InvocationResultRepo} from a directory of results
+     *
+     * @param testResultDir the parent directory of results
+     */
+    public InvocationResultRepo(File testResultDir) {
+        mResults = ResultHandler.getResults(testResultDir);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<IInvocationResult> getResults() {
+        return new ArrayList<IInvocationResult>(mResults);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IInvocationResult getResult(int sessionId) {
+        if (sessionId < 0 || sessionId >= mResults.size()) {
+            return null;
+        }
+        return mResults.get(sessionId);
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ModuleListener.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ModuleListener.java
new file mode 100644
index 0000000..acfba25
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ModuleListener.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.result;
+
+import com.android.compatibility.common.tradefed.testtype.IModuleDef;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.InputStreamSource;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.TestSummary;
+
+import java.util.Map;
+
+/**
+ * Listener for Compatibility test info.
+ * <p>
+ * This listener wraps around the normal listener to convert from module name to module id.
+ */
+public class ModuleListener implements IModuleListener {
+
+    private IModuleDef mModule;
+    private ITestInvocationListener mListener;
+
+    /**
+     * @param module
+     * @param listener
+     */
+    public ModuleListener(IModuleDef module, ITestInvocationListener listener) {
+        mModule = module;
+        mListener = listener;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void invocationStarted(IBuildInfo buildInfo) {
+        CLog.d("ModuleListener.invocationStarted(%s)", buildInfo.toString());
+        mListener.invocationStarted(buildInfo);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunStarted(String name, int numTests) {
+        CLog.d("ModuleListener.testRunStarted(%s, %d)", name, numTests);
+        mListener.testRunStarted(mModule.getId(), numTests);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testStarted(TestIdentifier test) {
+        CLog.d("ModuleListener.testStarted(%s)", test.toString());
+        mListener.testStarted(test);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testEnded(TestIdentifier test, Map<String, String> metrics) {
+        CLog.d("ModuleListener.testEnded(%s, %s)", test.toString(), metrics.toString());
+        mListener.testEnded(test, metrics);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testIgnored(TestIdentifier test) {
+        CLog.d("ModuleListener.testIgnored(%s)", test.toString());
+        mListener.testIgnored(test);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testFailed(TestIdentifier test, String trace) {
+        CLog.d("ModuleListener.testFailed(%s, %s)", test.toString(), trace);
+        mListener.testFailed(test, trace);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testAssumptionFailure(TestIdentifier test, String trace) {
+        CLog.d("ModuleListener.testAssumptionFailure(%s, %s)", test.toString(), trace);
+        mListener.testAssumptionFailure(test, trace);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunStopped(long elapsedTime) {
+        CLog.d("ModuleListener.testRunStopped(%d)", elapsedTime);
+        mListener.testRunStopped(elapsedTime);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunEnded(long elapsedTime, Map<String, String> metrics) {
+        CLog.d("ModuleListener.testRunEnded(%d, %s)", elapsedTime, metrics.toString());
+        mListener.testRunEnded(elapsedTime, metrics);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunFailed(String id) {
+        CLog.d("ModuleListener.testRunFailed(%s)", id);
+        mListener.testRunFailed(mModule.getId());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public TestSummary getSummary() {
+        return mListener.getSummary();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void invocationEnded(long elapsedTime) {
+        CLog.d("ModuleListener.invocationEnded(%d)", elapsedTime);
+        mListener.invocationEnded(elapsedTime);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void invocationFailed(Throwable cause) {
+        CLog.d("ModuleListener.invocationFailed(%s)", cause.toString());
+        mListener.invocationFailed(cause);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testLog(String name, LogDataType type, InputStreamSource stream) {
+        CLog.d("ModuleListener.testLog(%s, %s, %s)", name, type.toString(), stream.toString());
+        mListener.testLog(name, type, stream);
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
new file mode 100644
index 0000000..0bfc41c
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.result;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.compatibility.common.util.ICaseResult;
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.IModuleResult;
+import com.android.compatibility.common.util.ITestResult;
+import com.android.compatibility.common.util.InvocationResult;
+import com.android.compatibility.common.util.MetricsStore;
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultHandler;
+import com.android.compatibility.common.util.ResultUploader;
+import com.android.compatibility.common.util.TestStatus;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.Option.Importance;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ILogSaver;
+import com.android.tradefed.result.ILogSaverListener;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.ITestSummaryListener;
+import com.android.tradefed.result.InputStreamSource;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.LogFile;
+import com.android.tradefed.result.LogFileSaver;
+import com.android.tradefed.result.TestSummary;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.StreamUtil;
+import com.android.tradefed.util.TimeUtil;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Reporter for Compatibility test results.
+ */
+@OptionClass(alias="result-reporter")
+public class ResultReporter implements ILogSaverListener, ITestInvocationListener,
+       ITestSummaryListener {
+
+    private static final String RESULT_KEY = "COMPATIBILITY_TEST_RESULT";
+    private static final String DEVICE_INFO_GENERIC = "DEVICE_INFO_GENERIC_";
+    private static final String[] RESULT_RESOURCES = {
+        "compatibility_result.css",
+        "compatibility_result.xsd",
+        "compatibility_result.xsl",
+        "logo.png",
+        "newrule_green.png"};
+
+    @Option(name = CompatibilityTest.RETRY_OPTION,
+            shortName = 'r',
+            description = "retry a previous session.",
+            importance = Importance.IF_UNSET)
+    private Integer mRetrySessionId = null;
+
+    @Option(name = "quiet-output", description = "Mute display of test results.")
+    private boolean mQuietOutput = false;
+
+    @Option(name = "result-server", description = "Server to publish test results.")
+    private String mResultServer;
+
+    @Option(name = "include-test-log-tags", description = "Include test log tags in report.")
+    private boolean mIncludeTestLogTags = false;
+
+    @Option(name = "use-log-saver", description = "Also saves generated result with log saver")
+    private boolean mUseLogSaver = false;
+
+    private String mDeviceSerial;
+
+    private boolean mInitialized;
+    private IInvocationResult mResult;
+    private File mResultDir = null;
+    private File mLogDir = null;
+    private long mStartTime;
+    private ResultUploader mUploader;
+    private String mReferenceUrl;
+    private IModuleResult mCurrentModuleResult;
+    private ICaseResult mCurrentCaseResult;
+    private ITestResult mCurrentResult;
+    private IBuildInfo mBuild;
+    private CompatibilityBuildHelper mBuildHelper;
+    private ILogSaver mLogSaver;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void invocationStarted(IBuildInfo buildInfo) {
+        mInitialized = false;
+        mBuild = buildInfo;
+        mBuildHelper = new CompatibilityBuildHelper(mBuild);
+        mDeviceSerial = buildInfo.getDeviceSerial();
+        if (mDeviceSerial == null) {
+            mDeviceSerial = "unknown_device";
+        }
+        long time = System.currentTimeMillis();
+        String dirSuffix = getDirSuffix(time);
+        if (mRetrySessionId != null) {
+            Log.d(mDeviceSerial, String.format("Retrying session %d", mRetrySessionId));
+            List<IInvocationResult> results = null;
+            try {
+                results = ResultHandler.getResults(mBuildHelper.getResultsDir());
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            }
+            if (results != null && mRetrySessionId >= 0 && mRetrySessionId < results.size()) {
+                mResult = results.get(mRetrySessionId);
+            } else {
+                throw new IllegalArgumentException(
+                        String.format("Could not find session %d",mRetrySessionId));
+            }
+            mStartTime = mResult.getStartTime();
+            mResultDir = mResult.getResultDir();
+        } else {
+            mStartTime = time;
+            try {
+                mResultDir = new File(mBuildHelper.getResultsDir(), dirSuffix);
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            }
+            if (mResultDir != null && mResultDir.mkdirs()) {
+                logResult("Created result dir %s", mResultDir.getAbsolutePath());
+            } else {
+                throw new IllegalArgumentException(String.format("Could not create result dir %s",
+                        mResultDir.getAbsolutePath()));
+            }
+            mResult = new InvocationResult(mStartTime, mResultDir);
+        }
+        mBuildHelper.setResultDir(mResultDir.getName());
+        mUploader = new ResultUploader(mResultServer, mBuildHelper.getSuiteName());
+        try {
+            mLogDir = new File(mBuildHelper.getLogsDir(), dirSuffix);
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+        if (mLogDir != null && mLogDir.mkdirs()) {
+            logResult("Created log dir %s", mLogDir.getAbsolutePath());
+        } else {
+            throw new IllegalArgumentException(String.format("Could not create log dir %s",
+                    mLogDir.getAbsolutePath()));
+        }
+        mInitialized = true;
+    }
+
+    /**
+     * @return a {@link String} to use for directory suffixes created from the given time.
+     */
+    private String getDirSuffix(long time) {
+        return new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss").format(new Date(time));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunStarted(String id, int numTests) {
+        logResult("Starting %s with %d test%s", id, numTests, (numTests > 1) ? "s" : "");
+        mCurrentModuleResult = mResult.getOrCreateModule(id);
+        mResult.addDeviceSerial(mDeviceSerial);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testStarted(TestIdentifier test) {
+        mCurrentCaseResult = mCurrentModuleResult.getOrCreateResult(test.getClassName());
+        mCurrentResult = mCurrentCaseResult.getOrCreateResult(test.getTestName());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testEnded(TestIdentifier test, Map<String, String> metrics) {
+        if (mCurrentResult.getResultStatus() == TestStatus.FAIL) {
+            // Test has already failed.
+            return;
+        }
+        // device test can have performance results in test metrics
+        String perfResult = metrics.get(RESULT_KEY);
+        ReportLog report = null;
+        if (perfResult != null) {
+            try {
+                report = ReportLog.parse(perfResult);
+            } catch (XmlPullParserException | IOException e) {
+                e.printStackTrace();
+            }
+        } else {
+            // host test should be checked into MetricsStore.
+            report = MetricsStore.removeResult(
+                    mDeviceSerial, mCurrentModuleResult.getAbi(), test.toString());
+        }
+        mCurrentResult.passed(report);
+        logResult("%s passed", test);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testIgnored(TestIdentifier test) {
+        logResult("%s ignored", test);
+        // ignore
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testFailed(TestIdentifier test, String trace) {
+        mCurrentResult.failed(trace);
+        logResult("%s failed: %s", test, trace);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testAssumptionFailure(TestIdentifier test, String trace) {
+        mCurrentResult.failed(trace);
+        logResult("%s failed assumption: %s", test, trace);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunStopped(long elapsedTime) {
+        logResult("%s stopped after %s", mCurrentModuleResult.getId(),
+                TimeUtil.formatElapsedTime(elapsedTime));
+        // ignore
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunEnded(long elapsedTime, Map<String, String> metrics) {
+        // Check build attributes to add generic device info to report.
+        Map<String, String> buildAttributes = mBuild.getBuildAttributes();
+        for (Map.Entry<String, String> attributeEntry : buildAttributes.entrySet()) {
+            String key = attributeEntry.getKey();
+            String value = attributeEntry.getValue();
+            if (key.startsWith(DEVICE_INFO_GENERIC)) {
+                mResult.addBuildInfo(key.substring(DEVICE_INFO_GENERIC.length()), value);
+            }
+        }
+        mCurrentModuleResult.addRuntime(elapsedTime);
+        logResult("%s completed in %s. %d passed, %d failed, %d not executed",
+                mCurrentModuleResult.getId(),
+                TimeUtil.formatElapsedTime(elapsedTime),
+                mCurrentModuleResult.countResults(TestStatus.PASS),
+                mCurrentModuleResult.countResults(TestStatus.FAIL),
+                mCurrentModuleResult.countResults(TestStatus.NOT_EXECUTED));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunFailed(String id) {
+        logResult("%s failed to run", id);
+        // ignore
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public TestSummary getSummary() {
+        // ignore
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void putSummary(List<TestSummary> summaries) {
+        if (summaries.size() > 0) {
+            mReferenceUrl = summaries.get(0).getSummary().getString();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void invocationEnded(long elapsedTime) {
+        if (mInitialized) {
+            logResult("Invocation completed in %s. %d passed, %d failed, %d not executed",
+                    TimeUtil.formatElapsedTime(elapsedTime),
+                    mResult.countResults(TestStatus.PASS),
+                    mResult.countResults(TestStatus.FAIL),
+                    mResult.countResults(TestStatus.NOT_EXECUTED));
+            try {
+                File resultFile = ResultHandler.writeResults(mBuildHelper.getSuiteName(),
+                        mBuildHelper.getSuiteVersion(), mBuildHelper.getSuitePlan(), mResult,
+                        mResultDir, mStartTime, elapsedTime + mStartTime, mReferenceUrl);
+                copyDynamicConfigFiles(mBuildHelper.getDynamicConfigFiles(), mResultDir);
+                copyFormattingFiles(mResultDir);
+                zipResults(mResultDir);
+                if (mUseLogSaver) {
+                    FileInputStream fis = null;
+                    try {
+                        fis = new FileInputStream(resultFile);
+                        mLogSaver.saveLogData("log-result", LogDataType.XML, fis);
+                    } catch (IOException ioe) {
+                        Log.e(mDeviceSerial, "error saving XML with log saver");
+                        Log.e(mDeviceSerial, ioe);
+                    } finally {
+                        StreamUtil.close(fis);
+                    }
+                }
+                if (mResultServer != null && !mResultServer.trim().isEmpty()) {
+                    mUploader.uploadResult(resultFile, mReferenceUrl);
+                }
+            } catch (IOException | XmlPullParserException e) {
+                CLog.e(e);
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void invocationFailed(Throwable cause) {
+        logResult("ResultReporter.invocationFailed(%s)", cause);
+        mInitialized = false;
+        // Clean up
+        mResultDir.delete();
+        mResultDir = null;
+        mLogDir.delete();
+        mLogDir = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testLog(String name, LogDataType type, InputStreamSource stream) {
+        try {
+            LogFileSaver saver = new LogFileSaver(mLogDir);
+            File logFile = saver.saveAndZipLogData(name, type, stream.createInputStream());
+            logResult("Saved logs for %s in %s", name, logFile.getAbsolutePath());
+        } catch (IOException e) {
+            logResult("Failed to write log for %s", name);
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testLogSaved(String dataName, LogDataType dataType, InputStreamSource dataStream,
+            LogFile logFile) {
+        if (mIncludeTestLogTags && mCurrentResult != null
+                && dataName.startsWith(mCurrentResult.getFullName())) {
+            if (dataType == LogDataType.BUGREPORT) {
+                mCurrentResult.setBugReport(logFile.getUrl());
+            } else if (dataType == LogDataType.LOGCAT) {
+                mCurrentResult.setLog(logFile.getUrl());
+            } else if (dataType == LogDataType.PNG) {
+                mCurrentResult.setScreenshot(logFile.getUrl());
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setLogSaver(ILogSaver saver) {
+        mLogSaver = saver;
+    }
+
+    /**
+     * Copy the xml formatting files stored in this jar to the results directory
+     *
+     * @param resultsDir
+     */
+    static void copyFormattingFiles(File resultsDir) {
+        for (String resultFileName : RESULT_RESOURCES) {
+            InputStream configStream = ResultHandler.class.getResourceAsStream(
+                    String.format("/report/%s", resultFileName));
+            if (configStream != null) {
+                File resultFile = new File(resultsDir, resultFileName);
+                try {
+                    FileUtil.writeToFile(configStream, resultFile);
+                } catch (IOException e) {
+                    Log.w(ResultReporter.class.getSimpleName(),
+                            String.format("Failed to write %s to file", resultFileName));
+                }
+            } else {
+                Log.w(ResultReporter.class.getSimpleName(),
+                        String.format("Failed to load %s from jar", resultFileName));
+            }
+        }
+    }
+
+    /**
+     * move the dynamic config files to the results directory
+     *
+     * @param configFiles
+     * @param resultsDir
+     */
+    static void copyDynamicConfigFiles(Map<String, File> configFiles, File resultsDir) {
+        if (configFiles.size() == 0) return;
+
+        File folder = new File(resultsDir, "config");
+        folder.mkdir();
+        for (String moduleName : configFiles.keySet()) {
+            File resultFile = new File(folder, moduleName+".dynamic");
+            try {
+                FileUtil.copyFile(configFiles.get(moduleName), resultFile);
+                FileUtil.deleteFile(configFiles.get(moduleName));
+            } catch (IOException e) {
+                Log.w(ResultReporter.class.getSimpleName(),
+                        String.format("Failed to copy config file for %s to file", moduleName));
+            }
+        }
+    }
+
+    /**
+     * Zip the contents of the given results directory.
+     *
+     * @param resultsDir
+     */
+    @SuppressWarnings("deprecation")
+    private static void zipResults(File resultsDir) {
+        try {
+            // create a file in parent directory, with same name as resultsDir
+            File zipResultFile = new File(resultsDir.getParent(), String.format("%s.zip",
+                    resultsDir.getName()));
+            FileUtil.createZip(resultsDir, zipResultFile);
+        } catch (IOException e) {
+            Log.w(ResultReporter.class.getSimpleName(),
+                    String.format("Failed to create zip for %s", resultsDir.getName()));
+        }
+    }
+
+    /**
+     * @return the mResult
+     */
+    public IInvocationResult getResult() {
+        return mResult;
+    }
+
+    private void logResult(String format, Object... args) {
+        if (mQuietOutput) {
+            CLog.i(format, args);
+        } else {
+            Log.logAndDisplay(LogLevel.INFO, mDeviceSerial, String.format(format, args));
+        }
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java
new file mode 100644
index 0000000..7773d7d
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.targetprep.TestAppInstallSetup;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * Installs specified APKs from Compatibility repository.
+ */
+@OptionClass(alias="apk-installer")
+public class ApkInstaller extends TestAppInstallSetup {
+
+    private CompatibilityBuildHelper mBuildHelper = null;
+
+    protected File getTestsDir(IBuildInfo buildInfo) throws FileNotFoundException {
+        if (mBuildHelper == null) {
+            mBuildHelper = new CompatibilityBuildHelper(buildInfo);
+        }
+        return mBuildHelper.getTestsDir();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected File getLocalPathForFilename(IBuildInfo buildInfo, String apkFileName)
+            throws TargetSetupError {
+        File apkFile = null;
+        try {
+            apkFile = new File(getTestsDir(buildInfo), apkFileName);
+            if (!apkFile.isFile()) {
+                throw new FileNotFoundException();
+            }
+        } catch (FileNotFoundException e) {
+            throw new TargetSetupError(String.format("%s not found", apkFileName), e);
+        }
+        return apkFile;
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
new file mode 100644
index 0000000..916e8ec
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.compatibility.common.tradefed.util.NoOpTestInvocationListener;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.Option.Importance;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetCleaner;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.testtype.AndroidJUnitTest;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Target preparer that instruments an APK.
+ */
+@OptionClass(alias="apk-instrumentation-preparer")
+public class ApkInstrumentationPreparer extends PreconditionPreparer implements ITargetCleaner {
+
+    @Option(name = "apk", description = "Name of the apk to instrument", mandatory = true)
+    protected String mApkFileName = null;
+
+    @Option(name = "package", description = "Name of the package", mandatory = true)
+    protected String mPackageName = null;
+
+    @Option(name = CompatibilityTest.INCLUDE_FILTER_OPTION,
+            description = "the include module filters to apply.",
+            importance = Importance.ALWAYS)
+    private List<String> mIncludeFilters = new ArrayList<>();
+
+    @Option(name = CompatibilityTest.EXCLUDE_FILTER_OPTION,
+            description = "the exclude module filters to apply.",
+            importance = Importance.ALWAYS)
+    private List<String> mExcludeFilters = new ArrayList<>();
+
+    public enum When {
+        BEFORE, AFTER, BOTH;
+    }
+
+    @Option(name = "when", description = "When to instrument the apk", mandatory = true)
+    protected When mWhen = null;
+
+    protected ConcurrentHashMap<TestIdentifier, Map<String, String>> testMetrics =
+            new ConcurrentHashMap<>();
+    private ConcurrentHashMap<TestIdentifier, String> testFailures = new ConcurrentHashMap<>();
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+            BuildError, DeviceNotAvailableException {
+        if (mWhen == When.AFTER) {
+            return;
+        }
+        try {
+            if (!instrument(device, buildInfo)) {
+                throw new TargetSetupError("Not all target preparation steps completed");
+            }
+        } catch (FileNotFoundException e) {
+            throw new TargetSetupError("Couldn't find apk to instrument", e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
+            throws DeviceNotAvailableException {
+        if (e instanceof DeviceNotAvailableException) {
+            return;
+        }
+        if (mWhen == When.BEFORE) {
+            return;
+        }
+        try {
+            instrument(device, buildInfo);
+        } catch (FileNotFoundException e1) {
+            CLog.e("Couldn't find apk to instrument");
+            CLog.e(e1);
+        }
+    }
+
+    private boolean instrument(ITestDevice device, IBuildInfo buildInfo)
+            throws DeviceNotAvailableException, FileNotFoundException {
+        ITestInvocationListener listener = new TargetPreparerListener();
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
+
+        File testsDir = buildHelper.getTestsDir();
+        File apkFile = new File(testsDir, mApkFileName);
+        if (!apkFile.exists()) {
+            throw new FileNotFoundException(String.format("%s not found", mApkFileName));
+        }
+
+        AndroidJUnitTest instrTest = new AndroidJUnitTest();
+        instrTest.setDevice(device);
+        instrTest.setInstallFile(apkFile);
+        instrTest.setPackageName(mPackageName);
+        instrTest.addAllIncludeFilters(mIncludeFilters);
+        instrTest.addAllExcludeFilters(mExcludeFilters);
+        instrTest.run(listener);
+        boolean success = true;
+        if (!testFailures.isEmpty()) {
+            for (TestIdentifier test : testFailures.keySet()) {
+                success = false;
+                String trace = testFailures.get(test);
+                CLog.e("Target preparation step %s failed.\n%s", test.getTestName(), trace);
+            }
+        }
+        return success;
+    }
+
+    public class TargetPreparerListener extends NoOpTestInvocationListener {
+
+        @Override
+        public void testEnded(TestIdentifier test, Map<String, String> metrics) {
+            testMetrics.put(test, metrics);
+        }
+
+        @Override
+        public void testFailed(TestIdentifier test, String trace) {
+            testFailures.put(test, trace);
+        }
+
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkPreconditionCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkPreconditionCheck.java
new file mode 100644
index 0000000..0f0b6c2
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkPreconditionCheck.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.tradefed.config.OptionClass;
+
+/**
+ * Runs a precondition test by instrumenting an APK
+ */
+@OptionClass(alias="apk-precondition-check")
+public class ApkPreconditionCheck extends ApkInstrumentationPreparer {
+
+    public ApkPreconditionCheck() {
+        mWhen = When.BEFORE;
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
new file mode 100644
index 0000000..c178d9c
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Map;
+
+/**
+ * An {@link ApkInstrumentationPreparer} that collects device info.
+ */
+public class DeviceInfoCollector extends ApkInstrumentationPreparer {
+
+    private static String LOG_TAG = "DeviceInfoCollector";
+    private static String DEVICE_INFO_CLASS = "com.android.compatibility.common.deviceinfo";
+    private static String DEVICE_INFO_GENERIC = "DEVICE_INFO_GENERIC_";
+    private static String DEVICE_INFO_ERROR = "DEVICE_INFO_ERROR_";
+
+    @Option(name = CompatibilityTest.SKIP_DEVICE_INFO_OPTION, description =
+            "Whether device info collection should be skipped")
+    private boolean mSkipDeviceInfo = false;
+
+    @Option(name= "src-dir", description = "The directory to copy to the results dir")
+    private String mSrcDir;
+
+    @Option(name = "dest-dir", description = "The directory under the result to store the files")
+    private String mDestDir;
+
+    public DeviceInfoCollector() {
+        mWhen = When.BEFORE;
+    }
+
+    @Override
+    public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+            BuildError, DeviceNotAvailableException {
+        if (mSkipDeviceInfo) {
+            return;
+        }
+
+        run(device, buildInfo);
+
+        // Check test metrics for errors and copy generic device info results to build attribute.
+        for (Map.Entry<TestIdentifier, Map<String, String>> metricEntry : testMetrics.entrySet()) {
+            if (!metricEntry.getKey().getClassName().startsWith(DEVICE_INFO_CLASS)) {
+                continue;
+            }
+            for (Map.Entry<String, String> testEntry : metricEntry.getValue().entrySet()) {
+                String key = testEntry.getKey();
+                String value = testEntry.getValue();
+                if (key.startsWith(DEVICE_INFO_ERROR)) {
+                    throw new TargetSetupError(String.format("[%s] %s", key, value));
+                }
+                if (key.startsWith(DEVICE_INFO_GENERIC)) {
+                    buildInfo.addBuildAttribute(key, value);
+                }
+            }
+        }
+
+        getDeviceInfoFiles(device, buildInfo);
+    }
+
+    private void getDeviceInfoFiles(ITestDevice device, IBuildInfo buildInfo) {
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
+        try {
+            File resultDir = buildHelper.getResultDir();
+            if (mDestDir != null) {
+                resultDir = new File(resultDir, mDestDir);
+            }
+            resultDir.mkdirs();
+            if (!resultDir.isDirectory()) {
+                CLog.e(LOG_TAG, String.format("% is not a directory", resultDir.getAbsolutePath()));
+                return;
+            }
+            String resultPath = resultDir.getAbsolutePath();
+            pull(device, mSrcDir, resultPath);
+        } catch (FileNotFoundException fnfe) {
+            fnfe.printStackTrace();
+        }
+    }
+
+    private void pull(ITestDevice device, String src, String dest) {
+        String command = String.format("adb -s %s pull %s %s", device.getSerialNumber(), src, dest);
+        try {
+            Process p = Runtime.getRuntime().exec(new String[] {"/bin/bash", "-c", command});
+            if (p.waitFor() != 0) {
+                CLog.e(LOG_TAG, String.format("Failed to run %s", command));
+            }
+        } catch (Exception e) {
+            CLog.e(LOG_TAG, e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
new file mode 100644
index 0000000..8c455cd
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.util.DynamicConfig;
+import com.android.compatibility.common.util.DynamicConfigHandler;
+import com.android.ddmlib.Log;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetCleaner;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.StreamUtil;
+
+import org.json.JSONException;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+
+/**
+ * Pushes dynamic config files from config repository
+ */
+@OptionClass(alias="dynamic-config-pusher")
+public class DynamicConfigPusher implements ITargetCleaner {
+    public enum TestTarget {
+        DEVICE,
+        HOST
+    }
+
+    private static final String LOG_TAG = DynamicConfigPusher.class.getSimpleName();
+
+    @Option(name = "cleanup", description = "Whether to clean up config files after test is done.")
+    private boolean mCleanup = true;
+
+    @Option(name="module-name", description = "Specify the module name")
+    private String mModuleName;
+
+    @Option(name = "target", description = "Specify the target, 'device' or 'host'")
+    private TestTarget mTarget;
+
+    @Option(name = "version-name", description = "Specify the version for override config")
+    private static String mVersion;
+
+
+    private String mFilePushed;
+
+    void setModuleName(String moduleName) {
+        mModuleName = moduleName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, BuildError,
+            DeviceNotAvailableException {
+
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
+
+        File localConfigFile = null;
+        try {
+            localConfigFile = DynamicConfig.getConfigFile(buildHelper.getTestsDir(), mModuleName);
+        } catch (FileNotFoundException e) {
+            throw new TargetSetupError(
+                    "Cannot get local dynamic config file from test directory", e);
+        }
+
+        String apfeConfigInJson = null;
+        String OriginUrl = buildHelper.getDynamicConfigUrl();
+
+        if (OriginUrl != null) {
+            try {
+                String requestUrl = OriginUrl
+                        .replace("{module-name}", mModuleName).replace("{version-name}", mVersion);
+                java.net.URL request = new URL(requestUrl);
+                apfeConfigInJson = StreamUtil.getStringFromStream(request.openStream());
+            } catch (IOException e) {
+                LogUtil.printLog(Log.LogLevel.WARN, LOG_TAG,
+                        "Cannot download and parse json config from Url");
+            }
+        } else {
+            LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG,
+                    "Dynamic config override Url is not set");
+        }
+
+        File src = null;
+        try {
+            src = DynamicConfigHandler.getMergedDynamicConfigFile(
+                    localConfigFile, apfeConfigInJson, mModuleName);
+        } catch (IOException | XmlPullParserException | JSONException e) {
+            throw new TargetSetupError("Cannot get merged dynamic config file", e);
+        }
+
+        switch (mTarget) {
+            case DEVICE:
+                String deviceDest = DynamicConfig.CONFIG_FOLDER_ON_DEVICE + src.getName();
+                if (!device.pushFile(src, deviceDest)) {
+                    throw new TargetSetupError(String.format(
+                            "Failed to push local '%s' to remote '%s'",
+                            src.getAbsolutePath(), deviceDest));
+                } else {
+                    mFilePushed = deviceDest;
+                    buildHelper.addDynamicConfigFile(mModuleName, src);
+                }
+                break;
+
+            case HOST:
+                File storageDir = new File(DynamicConfig.CONFIG_FOLDER_ON_HOST);
+                if (!storageDir.exists()) storageDir.mkdir();
+                File hostDest = new File(DynamicConfig.CONFIG_FOLDER_ON_HOST + src.getName());
+                try {
+                    FileUtil.copyFile(src, hostDest);
+                } catch (IOException e) {
+                    throw new TargetSetupError(String.format("Failed to copy file from %s to %s",
+                            src.getAbsolutePath(), hostDest.getAbsolutePath()), e);
+                }
+                mFilePushed = hostDest.getAbsolutePath();
+                buildHelper.addDynamicConfigFile(mModuleName, src);
+                break;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
+            throws DeviceNotAvailableException {
+        switch (mTarget) {
+            case DEVICE:
+                if (!(e instanceof DeviceNotAvailableException)
+                        && mCleanup && mFilePushed != null) {
+                    device.executeShellCommand("rm -r " + mFilePushed);
+                }
+                break;
+            case HOST:
+                new File(mFilePushed).delete();
+        }
+    }
+}
\ No newline at end of file
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
new file mode 100644
index 0000000..70dc125
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.PushFilePreparer;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * Pushes specified testing artifacts from Compatibility repository.
+ */
+@OptionClass(alias="file-pusher")
+public class FilePusher extends PushFilePreparer implements IAbiReceiver {
+
+    @Option(name = "append-bitness",
+            description = "Append the ABI's bitness to the filename.")
+    private boolean mAppendBitness = false;
+
+    private CompatibilityBuildHelper mBuildHelper = null;
+
+    private IAbi mAbi;
+
+    protected File getTestsDir(IBuildInfo buildInfo) throws FileNotFoundException {
+        if (mBuildHelper == null) {
+            mBuildHelper = new CompatibilityBuildHelper(buildInfo);
+        }
+        return mBuildHelper.getTestsDir();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public File resolveRelativeFilePath(IBuildInfo buildInfo, String fileName) {
+        try {
+            File f = new File(getTestsDir(buildInfo),
+                    String.format("%s%s", fileName, mAppendBitness ? mAbi.getBitness() : ""));
+            CLog.logAndDisplay(LogLevel.INFO, "Copying from %s", f.getAbsolutePath());
+            return f;
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
new file mode 100644
index 0000000..cea3136
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+/**
+ * Checks that location is enabled for GPS or Network before running a compatibility test
+ */
+@OptionClass(alias="location-check")
+public class LocationCheck extends SettingsPreparer {
+
+    private static final String LOCATION_SETTING = "location_providers_allowed";
+
+    private static final String GPS = "gps";
+    private static final String NETWORK = "network";
+
+    private static final String GPS_FEATURE = "android.hardware.location.gps";
+    private static final String NETWORK_FEATURE = "android.hardware.location.network";
+
+
+    private boolean hasLocationFeature(ITestDevice device) throws DeviceNotAvailableException {
+        String adbFeatures = device.executeShellCommand("pm list features");
+        return (adbFeatures.contains(GPS_FEATURE) || adbFeatures.contains(NETWORK_FEATURE));
+    }
+
+    @Override
+    public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+            BuildError, DeviceNotAvailableException {
+
+        if (!hasLocationFeature(device)) {
+            return; // skip this precondition if required location feature is not present
+        }
+
+        mSettingName = LOCATION_SETTING;
+        mSettingType = SettingsPreparer.SettingType.SECURE;
+        mExpectedSettingValues.add(NETWORK);
+        mExpectedSettingValues.add(GPS);
+        mExpectedSettingValues.add(String.format("%s,%s", GPS, NETWORK));
+        mExpectedSettingValues.add(String.format("%s,%s", NETWORK, GPS));
+        mFailureMessage = "Location services must be enabled via GPS or Network in order to " +
+                "successfully run the test suite";
+        super.run(device, buildInfo);
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java
new file mode 100644
index 0000000..5c94c27
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+/**
+ * An {@link ITargetPreparer} that performs checks and/or tasks to ensure the 
+ * the device is ready to run the test suite.
+ */
+public abstract class PreconditionPreparer implements ITargetPreparer {
+
+    @Option(name = CompatibilityTest.SKIP_PRECONDITIONS_OPTION, description =
+            "Whether preconditions should be skipped")
+    private boolean mSkipPreconditions = false;
+
+    @Override
+    public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+            BuildError, DeviceNotAvailableException {
+        if (!mSkipPreconditions) {
+            run(device, buildInfo);
+        }
+    }
+
+    public abstract void run(ITestDevice device, IBuildInfo buildInfo)
+            throws TargetSetupError, BuildError, DeviceNotAvailableException;
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
new file mode 100644
index 0000000..5d2baa7
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.ddmlib.Log;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+/**
+ * Checks that a device property is as expected
+ */
+@OptionClass(alias="property-check")
+public class PropertyCheck extends PreconditionPreparer {
+
+    @Option(name = "property-name", description = "The name of the property to check",
+            mandatory = true)
+    protected String mPropertyName = null;
+
+    @Option(name = "expected-value", description = "The expected value of the property",
+            mandatory = true)
+    protected String mExpectedPropertyValue = null;
+
+    @Option(name = "throw-error",
+            description = "Whether to throw an error for an unexpected property value")
+    protected boolean mThrowError = false;
+
+    private static final String LOG_TAG = PropertyCheck.class.getSimpleName();
+
+    @Override
+    public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+            BuildError, DeviceNotAvailableException {
+        String propertyValue = device.getProperty(mPropertyName);
+        if (propertyValue == null) {
+            throw new TargetSetupError(String.format(
+                    "Device property \"%s\" not found.", mPropertyName));
+        }
+
+        if (!mExpectedPropertyValue.equalsIgnoreCase(propertyValue)) {
+            String msg = String.format("Expected \"%s\" but found \"%s\" for property: %s",
+                    mExpectedPropertyValue, propertyValue, mPropertyName);
+            // Handle unexpected property value with either exception or warning
+            if(mThrowError) {
+                throw new TargetSetupError(msg);
+            } else {
+                LogUtil.printLog(Log.LogLevel.WARN, LOG_TAG, msg);
+            }
+        }
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ResultFilePuller.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ResultFilePuller.java
new file mode 100644
index 0000000..7b20997d
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ResultFilePuller.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetCleaner;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Pulls files from the device after a test run and puts them into the result folder.
+ */
+@OptionClass(alias="result-file-puller")
+public class ResultFilePuller implements ITargetCleaner {
+
+    private static final String LOG_TAG = ResultFilePuller.class.getSimpleName();
+
+    @Option(name="clear", description = "Whether to clear the src files and dirs before running the test")
+    private boolean mClearSrc = true;
+
+    @Option(name="src-file", description = "The file to copy to the results dir")
+    private List<String> mSrcFiles = new ArrayList<>();
+
+    @Option(name="src-dir", description = "The directory to copy to the results dir")
+    private List<String> mSrcDirs = new ArrayList<>();
+
+    @Option(name = "dest-dir", description = "The directory under the result to store the files")
+    private String mDestDir;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, BuildError,
+            DeviceNotAvailableException {
+        if (mClearSrc) {
+            for (String file : mSrcFiles) {
+                delete(device, file);
+            }
+            for (String dir : mSrcDirs) {
+                delete(device, dir);
+            }
+        }
+    }
+
+    private void delete(ITestDevice device, String file) throws DeviceNotAvailableException {
+        device.executeShellCommand(String.format("rm -rf %s", file));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
+            throws DeviceNotAvailableException {
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
+        try {
+            File resultDir = buildHelper.getResultDir();
+            if (mDestDir != null) {
+                resultDir = new File(resultDir, mDestDir);
+            }
+            resultDir.mkdirs();
+            if (!resultDir.isDirectory()) {
+                CLog.e(LOG_TAG, String.format("% is not a directory", resultDir.getAbsolutePath()));
+                return;
+            }
+            String resultPath = resultDir.getAbsolutePath();
+            for (String file : mSrcFiles) {
+                pull(device, file, resultPath);
+            }
+            for (String dir : mSrcDirs) {
+                pull(device, dir, resultPath);
+            }
+        } catch (FileNotFoundException fnfe) {
+            fnfe.printStackTrace();
+        }
+    }
+
+    private void pull(ITestDevice device, String src, String dest) {
+        String command = String.format("adb -s %s pull %s %s", device.getSerialNumber(), src, dest);
+        try {
+            Process p = Runtime.getRuntime().exec(new String[] {"/bin/bash", "-c", command});
+            if (p.waitFor() != 0) {
+                CLog.e(LOG_TAG, String.format("Failed to run %s", command));
+            }
+        } catch (Exception e) {
+            CLog.e(LOG_TAG, e);
+        }
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
new file mode 100644
index 0000000..f21ef39
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Checks that a given setting on the device is one of the given values
+ */
+@OptionClass(alias="settings-preparer")
+public class SettingsPreparer extends PreconditionPreparer {
+
+    public enum SettingType {
+        SECURE,
+        GLOBAL,
+        SYSTEM;
+    }
+
+    /* This option must be defined, but is not explicitly marked mandatory, as subclasses of
+     * the SettingsPreparer class can define mSettingName at runtime */
+    @Option(name = "device-setting", description = "The setting on the device to be checked")
+    protected String mSettingName = null;
+
+    /* This option must be defined, but is not explicitly marked mandatory, as subclasses of
+     * the SettingsPreparer class can define mSettingType at runtime */
+    @Option(name = "setting-type",
+            description = "If the setting is 'secure', 'global', or 'system'")
+    protected SettingType mSettingType = null;
+
+    @Option(name = "set-value", description = "The value to be set for the setting")
+    protected String mSetValue = null;
+
+    @Option(name = "expected-values", description = "The set of expected values of the setting")
+    protected List<String> mExpectedSettingValues = new ArrayList<String>();
+
+    @Option(name = "failure-message", description = "The text printed for an unexpected value")
+    protected String mFailureMessage = null;
+
+    @Override
+    public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+            BuildError, DeviceNotAvailableException {
+
+        if (mSettingName == null) {
+            throw new TargetSetupError("The \"device-setting\" option must be defined for the " +
+                    "SettingsPreparer class");
+        }
+
+        if (mSettingType == null) {
+            throw new TargetSetupError("The \"setting-type\" option must be defined for the " +
+                    "SettingsPreparer class");
+        }
+
+        /* At least one of the options "set-value" and "expected-values" must be set */
+        if (mSetValue == null && mExpectedSettingValues.isEmpty()) {
+            throw new TargetSetupError("At least one of the options \"set-value\" and " +
+                    "\"expected-values\" must be set");
+        }
+
+        String shellCmdGet = (!mExpectedSettingValues.isEmpty()) ?
+                String.format("settings get %s %s", mSettingType, mSettingName) : "";
+        String shellCmdPut = (mSetValue != null) ?
+                String.format("settings put %s %s %s", mSettingType, mSettingName, mSetValue) : "";
+
+
+        /* Case 1: Both expected-values and set-value are given */
+        if (mSetValue != null && !mExpectedSettingValues.isEmpty()) {
+            // first ensure that the set-value given can be found in expected-values
+            if (!mExpectedSettingValues.contains(mSetValue)) {
+                throw new TargetSetupError(String.format(
+                        "set-value for %s is %s, but value not found in expected-values: %s",
+                        mSettingName, mSetValue, mExpectedSettingValues.toString()));
+            }
+            String currentSettingValue = device.executeShellCommand(shellCmdGet).trim();
+            // only change unexpected setting value
+            if (!mExpectedSettingValues.contains(currentSettingValue)) {
+                device.executeShellCommand(shellCmdPut);
+            }
+            return;
+        }
+
+        /* Case 2: Only set-value given */
+        if (mSetValue != null) {
+            device.executeShellCommand(shellCmdPut);
+            return;
+        }
+
+        /* Case 3: Only expected-values given */
+        String currentSettingValue = device.executeShellCommand(shellCmdGet).trim();
+        if (!mExpectedSettingValues.contains(currentSettingValue)) {
+            if (mFailureMessage == null) {
+                mFailureMessage = String.format(
+                        "Device setting \"%s\" returned \"%s\", not found in %s",
+                        mSettingName, currentSettingValue, mExpectedSettingValues.toString());
+            }
+            throw new TargetSetupError(mFailureMessage);
+        }
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/StayAwakePreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/StayAwakePreparer.java
new file mode 100644
index 0000000..9745179
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/StayAwakePreparer.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.util.Arrays;
+
+/**
+ * Modifies the 'Stay Awake' setting of the device, so that the device's screen stays on
+ * whenever charging via USB
+ */
+@OptionClass(alias="stay-awake-preparer")
+public class StayAwakePreparer extends SettingsPreparer {
+
+    private static final String STAY_AWAKE_SETTING = "stay_on_while_plugged_in";
+
+    /*
+     * Values that are appropriate for the "Stay Awake" setting while running compatibility tests:
+     * (the second bit must be 'on' to allow screen to stay awake while charging via USB)
+     * 2 - Stay awake while charging via USB
+     * 3 - Stay awake while changing via USB or AC
+     * 6 - Stay awake while charging via USB or Wireless
+     * 7 - Stay awake while charging via USB or AC or Wireless
+     */
+    private static final String[] STAY_AWAKE_VALUES = new String[] {"2", "3", "6", "7"};
+    private static final String DEFAULT_VALUE = "2";
+
+    @Override
+    public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+            BuildError, DeviceNotAvailableException {
+
+        mSettingName = STAY_AWAKE_SETTING;
+        mSettingType = SettingsPreparer.SettingType.GLOBAL;
+        mSetValue = DEFAULT_VALUE;
+        for (String value : STAY_AWAKE_VALUES) {
+            mExpectedSettingValues.add(value);
+        }
+        super.run(device, buildInfo);
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java
new file mode 100644
index 0000000..54b6bc0
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * An {@link ITargetPreparer} that allows a test module to specify tokens that a device must have
+ * to run the tests contained.
+ *
+ * A token is string that is required by a test module and given to a device by the user, they are
+ * used by the scheduler to ensure tests are scheduled on the correct devices. Eg if the user is
+ * sharding the innvocation across 10 devices, they will not want to put a SIM card in every device,
+ * instead they can use a single SIM card and use tokens to tell the scheduler which device should
+ * be used to run the SIM card tests.
+ */
+public class TokenRequirement implements ITargetPreparer {
+
+    @Option(name = "token", description = "The token a device must have to run this module")
+    private Set<String> mTokens = new HashSet<>();
+
+    @Override
+    public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+            BuildError, DeviceNotAvailableException {
+        throw new TargetSetupError("TokenRequirement is not expected to run");
+    }
+
+    /**
+     * @return the {@link Set} of tokens required by this module.
+     */
+    public Set<String> getTokens() {
+        return mTokens;
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
new file mode 100644
index 0000000..0100969
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This preparer ensures that the device is connected to a network.
+ * The options "wifi-ssid" and "wifi-psk" allow users of the preparer to attempt connection
+ * to a network. If the options are provided, the preparer disconnects any existing network
+ * connection, and attempts to connect with the options provided.
+ *
+ * @throws TargetSetupError if device is not connected to a network and no options are given, or
+ * if the device fails to connect to the network specified in the options
+ */
+@OptionClass(alias="wifi-check")
+public class WifiCheck extends PreconditionPreparer {
+
+    private static final String WIFI_FEATURE = "android.hardware.wifi";
+
+    @Option(name = "wifi-ssid", description = "Name of the WiFi network with which to connect")
+    protected String mWifiSsid = null;
+
+    @Option(name = "wifi-psk",
+            description = "The WPA-PSK associated with the wifi-ssid option")
+    protected String mWifiPsk = null;
+
+    private boolean hasWifiFeature(ITestDevice device) throws DeviceNotAvailableException {
+        String pmFeatures = device.executeShellCommand("pm list features");
+        return pmFeatures.contains(WIFI_FEATURE);
+    }
+
+    @Override
+    public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+            BuildError, DeviceNotAvailableException {
+
+        if(!hasWifiFeature(device)) {
+            return; // skip this precondition check if device doesn't support wifi
+        }
+
+        if (mWifiSsid == null) { // no connection to create, check for existing connectivity
+            if (!device.checkConnectivity()) {
+                throw new TargetSetupError("Device has no network connection, no ssid provided");
+            }  
+        } else { // network provided in options, attempt to create new connection
+            CLog.logAndDisplay(LogLevel.INFO, "Attempting connection to \"%s\"", mWifiSsid);
+            if (device.connectToWifiNetwork(mWifiSsid, mWifiPsk)) { // attempt connection
+                CLog.logAndDisplay(LogLevel.INFO, "Connection successful");
+            } else {
+                throw new TargetSetupError(String.format(
+                        "Unable to connect to network \"%s\", some modules of CTS" +
+                        "require an active network connection", mWifiSsid));
+            }
+        }
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/Abi.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/Abi.java
new file mode 100644
index 0000000..fab990e
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/Abi.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.testtype.IAbi;
+
+/**
+ * A class representing an ABI.
+ *
+ * TODO(stuartscott): should be in TradeFed.
+ */
+public class Abi implements IAbi {
+
+    private final String mName;
+    private final String mBitness;
+
+    public Abi(String name, String bitness) {
+        mName = name;
+        mBitness = bitness;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getBitness() {
+        return mBitness;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        return mName;
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
new file mode 100644
index 0000000..eff3006
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.result.IInvocationResultRepo;
+import com.android.compatibility.common.tradefed.result.InvocationResultRepo;
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.compatibility.common.util.ICaseResult;
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.IModuleResult;
+import com.android.compatibility.common.util.ITestResult;
+import com.android.compatibility.common.util.TestFilter;
+import com.android.compatibility.common.util.TestStatus;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.Option.Importance;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.config.OptionCopier;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.util.AbiFormatter;
+import com.android.tradefed.util.ArrayUtil;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A Test for running Compatibility Suites
+ */
+@OptionClass(alias = "compatibility")
+public class CompatibilityTest implements IDeviceTest, IShardableTest, IBuildReceiver {
+
+    public static final String INCLUDE_FILTER_OPTION = "include-filter";
+    public static final String EXCLUDE_FILTER_OPTION = "exclude-filter";
+    private static final String PLAN_OPTION = "plan";
+    private static final String MODULE_OPTION = "module";
+    private static final String TEST_OPTION = "test";
+    private static final String MODULE_ARG_OPTION = "module-arg";
+    private static final String TEST_ARG_OPTION = "test-arg";
+    public static final String RETRY_OPTION = "retry";
+    private static final String ABI_OPTION = "abi";
+    private static final String SHARD_OPTION = "shards";
+    public static final String SKIP_DEVICE_INFO_OPTION = "skip-device-info";
+    public static final String SKIP_PRECONDITIONS_OPTION = "skip-preconditions";
+    public static final String DEVICE_TOKEN_OPTION = "device-token";
+    private static final String URL = "dynamic-config-url";
+
+    private static final TestStatus[] RETRY_TEST_STATUS = new TestStatus[] {
+            TestStatus.FAIL,
+            TestStatus.NOT_EXECUTED
+    };
+
+    @Option(name = PLAN_OPTION,
+            description = "the test suite plan to run, such as \"everything\" or \"cts\"",
+            importance = Importance.ALWAYS)
+    private String mSuitePlan;
+
+    @Option(name = INCLUDE_FILTER_OPTION,
+            description = "the include module filters to apply.",
+            importance = Importance.ALWAYS)
+    private List<String> mIncludeFilters = new ArrayList<>();
+
+    @Option(name = EXCLUDE_FILTER_OPTION,
+            description = "the exclude module filters to apply.",
+            importance = Importance.ALWAYS)
+    private List<String> mExcludeFilters = new ArrayList<>();
+
+    @Option(name = MODULE_OPTION,
+            shortName = 'm',
+            description = "the test module to run.",
+            importance = Importance.IF_UNSET)
+    private String mModuleName = null;
+
+    @Option(name = TEST_OPTION,
+            shortName = 't',
+            description = "the test run.",
+            importance = Importance.IF_UNSET)
+    private String mTestName = null;
+
+    @Option(name = MODULE_ARG_OPTION,
+            description = "the arguments to pass to a module. The expected format is"
+                    + "\"<module-name>:<arg-name>:<arg-value>\"",
+            importance = Importance.ALWAYS)
+    private List<String> mModuleArgs = new ArrayList<>();
+
+    @Option(name = TEST_ARG_OPTION,
+            description = "the arguments to pass to a test. The expected format is"
+                    + "\"<test-class>:<arg-name>:<arg-value>\"",
+            importance = Importance.ALWAYS)
+    private List<String> mTestArgs = new ArrayList<>();
+
+    @Option(name = RETRY_OPTION,
+            shortName = 'r',
+            description = "retry a previous session.",
+            importance = Importance.IF_UNSET)
+    private Integer mRetrySessionId = null;
+
+    @Option(name = ABI_OPTION,
+            shortName = 'a',
+            description = "the abi to test.",
+            importance = Importance.IF_UNSET)
+    private String mAbiName = null;
+
+    @Option(name = SHARD_OPTION,
+            description = "split the modules up to run on multiple devices concurrently.")
+    private int mShards = 1;
+
+    @Option(name = URL,
+            description = "Specify the url for override config")
+    private String mURL;
+
+    @Option(name = SKIP_DEVICE_INFO_OPTION,
+            description = "Whether device info collection should be skipped")
+    private boolean mSkipDeviceInfo = false;
+
+    @Option(name = SKIP_PRECONDITIONS_OPTION,
+            description = "Whether preconditions should be skipped")
+    private boolean mSkipPreconditions = false;
+
+    @Option(name = DEVICE_TOKEN_OPTION,
+            description = "Holds the devices' tokens, used when scheduling tests that have"
+                    + "prerequisits such as requiring a SIM card. Format is <serial>:<token>",
+            importance = Importance.ALWAYS)
+    private List<String> mDeviceTokens = new ArrayList<>();
+
+    @Option(name = "bugreport-on-failure",
+            description = "Take a bugreport on every test failure. " +
+                    "Warning: can potentially use a lot of disk space.")
+    private boolean mBugReportOnFailure = false;
+
+    @Option(name = "logcat-on-failure",
+            description = "Take a logcat snapshot on every test failure.")
+    private boolean mLogcatOnFailure = false;
+
+    @Option(name = "screenshot-on-failure",
+            description = "Take a screenshot on every test failure.")
+    private boolean mScreenshotOnFailure = false;
+
+    private int mTotalShards;
+    private ITestDevice mDevice;
+    private IBuildInfo mBuild;
+    private CompatibilityBuildHelper mBuildHelper;
+
+    /**
+     * Create a new {@link CompatibilityTest} that will run the default list of
+     * modules.
+     */
+    public CompatibilityTest() {
+        this(1 /* totalShards */);
+    }
+
+    /**
+     * Create a new {@link CompatibilityTest} that will run a sublist of
+     * modules.
+     */
+    public CompatibilityTest(int totalShards) {
+        if (totalShards < 1) {
+            throw new IllegalArgumentException(
+                    "Must be at least 1 shard. Given:" + totalShards);
+        }
+        mTotalShards = totalShards;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ITestDevice getDevice() {
+        return mDevice;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDevice(ITestDevice device) {
+        mDevice = device;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mBuild = buildInfo;
+        mBuildHelper = new CompatibilityBuildHelper(mBuild);
+        mBuildHelper.init(mSuitePlan, mURL);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+        boolean isInitializer = false;
+        try {
+            IModuleRepo moduleRepo = ModuleRepo.getInstance();
+            // Synchronized so only one shard enters and sets up the moduleRepo. When the other
+            // shards enter after this, moduleRepo is already initialized so they dont do anything
+            synchronized (moduleRepo) {
+                if (!moduleRepo.isInitialized()) {
+                    isInitializer = true;
+                    setupFilters();
+                    // Initialize the repository, {@link CompatibilityBuildHelper#getTestsDir} can
+                    // throw a {@link FileNotFoundException}
+                    moduleRepo.initialize(mTotalShards, mBuildHelper.getTestsDir(), getAbis(),
+                            mDeviceTokens, mTestArgs, mModuleArgs, mIncludeFilters,
+                            mExcludeFilters, mBuild);
+                }
+            }
+            // Get the tests to run in this shard
+            List<IModuleDef> modules = moduleRepo.getModules(getDevice().getSerialNumber());
+
+            listener = new FailureListener(listener, getDevice(), mBugReportOnFailure,
+                    mLogcatOnFailure, mScreenshotOnFailure);
+            int moduleCount = modules.size();
+            CLog.logAndDisplay(LogLevel.INFO, "Starting %d module%s on %s", moduleCount,
+                    (moduleCount > 1) ? "s" : "", mDevice.getSerialNumber());
+
+            // Set values and run preconditions
+            for (int i = 0; i < moduleCount; i++) {
+                IModuleDef module = modules.get(i);
+                module.setBuild(mBuild);
+                module.setDevice(mDevice);
+                module.prepare(mSkipPreconditions);
+            }
+            // Run the tests
+            for (int i = 0; i < moduleCount; i++) {
+                modules.get(i).run(listener);
+            }
+        } catch (DeviceNotAvailableException e) {
+            // Pass up
+            throw e;
+        } catch (FileNotFoundException | RuntimeException e) {
+            CLog.e(e);
+        } catch (Error e) {
+            CLog.e(e);
+        } finally {
+            if (isInitializer) {
+                ModuleRepo.tearDown();
+            }
+        }
+    }
+
+    /**
+     * Gets the set of ABIs supported by both Compatibility and the device under test
+     *
+     * @return The set of ABIs to run the tests on
+     * @throws DeviceNotAvailableException
+     */
+    Set<IAbi> getAbis() throws DeviceNotAvailableException {
+        Set<IAbi> abis = new HashSet<>();
+        for (String abi : AbiFormatter.getSupportedAbis(mDevice, "")) {
+            // Only test against ABIs supported by Compatibility, and if the
+            // --abi option was given, it must match.
+            if (AbiUtils.isAbiSupportedByCompatibility(abi)
+                    && (mAbiName == null || mAbiName.equals(abi))) {
+                abis.add(new Abi(abi, AbiUtils.getBitness(abi)));
+            }
+        }
+        if (abis == null || abis.isEmpty()) {
+            if (mAbiName == null) {
+                throw new IllegalArgumentException("Could not get device's ABIs");
+            } else {
+                throw new IllegalArgumentException(String.format(
+                        "Device %s doesn't support %s", mDevice.getSerialNumber(), mAbiName));
+            }
+        }
+        return abis;
+    }
+
+    /**
+     * Sets the include/exclude filters up based on if a module name was given or whether this is a
+     * retry run.
+     */
+    void setupFilters() {
+        if (mRetrySessionId != null) {
+            // We're retrying so clear the filters
+            mIncludeFilters.clear();
+            mExcludeFilters.clear();
+            mModuleName = null;
+            mTestName = null;
+            // Load the invocation result
+            IInvocationResultRepo repo;
+            IInvocationResult result = null;
+            try {
+                repo = new InvocationResultRepo(mBuildHelper.getResultsDir());
+                result = repo.getResult(mRetrySessionId);
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            }
+            if (result == null) {
+                throw new IllegalArgumentException(String.format(
+                        "Could not find session with id %d", mRetrySessionId));
+            }
+            // Append each test that failed or was not executed to the filters
+            for (IModuleResult module : result.getModules()) {
+                for (ICaseResult cr : module.getResults()) {
+                    for (TestStatus status : RETRY_TEST_STATUS) {
+                        for (ITestResult r : cr.getResults(status)) {
+                            // Create the filter for the test to be run.
+                            TestFilter filter = new TestFilter(
+                                    module.getAbi(), module.getName(), r.getFullName());
+                            mIncludeFilters.add(filter.toString());
+                            // Reset the result so that the test gets retried.
+                            r.reset();
+                        }
+                    }
+                }
+            }
+        } else if (mModuleName != null) {
+            mIncludeFilters.clear();
+            try {
+                List<String> modules = ModuleRepo.getModuleNamesMatching(
+                        mBuildHelper.getTestsDir(), mModuleName);
+                if (modules.size() == 0) {
+                    throw new IllegalArgumentException(
+                            String.format("No modules found matching %s", mModuleName));
+                } else if (modules.size() > 1) {
+                    throw new IllegalArgumentException(String.format(
+                            "Multiple modules found matching %s:\n%s\nWhich one did you mean?\n",
+                            mModuleName, ArrayUtil.join("\n", modules)));
+                } else {
+                    String module = modules.get(0);
+                    mIncludeFilters.add(new TestFilter(mAbiName, module, mTestName).toString());
+                    if (mTestName != null) {
+                        // We're filtering it down to the lowest level, no need to give excludes
+                        mExcludeFilters.clear();
+                    } else {
+                        // If we dont specify a test name, we only want to run this module with any
+                        // previous exclusions as long as they dont exclude the whole module.
+                        List<String> excludeFilters = new ArrayList<>();
+                        for (String excludeFilter : mExcludeFilters) {
+                            TestFilter filter = TestFilter.createFrom(excludeFilter);
+                            String name = filter.getName();
+                            // Add the filter if it applies to this module, and it has a test name
+                            if (module.equals(name) && filter.getTest() != null) {
+                                excludeFilters.add(excludeFilter);
+                            }
+                        }
+                        mExcludeFilters = excludeFilters;
+                    }
+                }
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            }
+        } else {
+            // If a module has an arg, assume it's included
+            for (String arg : mModuleArgs) {
+                mIncludeFilters.add(arg.split(":")[0]);
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Collection<IRemoteTest> split() {
+        if (mShards <= 1) {
+            return null;
+        }
+
+        List<IRemoteTest> shardQueue = new LinkedList<>();
+        for (int i = 0; i < mShards; i++) {
+            CompatibilityTest test = new CompatibilityTest(mShards);
+            OptionCopier.copyOptionsNoThrow(this, test);
+            // Set the shard count because the copy option on the previous line
+            // copies over the mShard value
+            test.mShards = 0;
+            shardQueue.add(test);
+        }
+
+        return shardQueue;
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/FailureListener.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/FailureListener.java
new file mode 100644
index 0000000..c3509d1
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/FailureListener.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.InputStreamSource;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.ResultForwarder;
+import com.android.tradefed.util.RunUtil;
+
+public class FailureListener extends ResultForwarder {
+
+    private static final int MAX_LOGCAT_BYTES = 500 * 1024; // 500K
+
+    private ITestDevice mDevice;
+    private boolean mBugReportOnFailure;
+    private boolean mLogcatOnFailure;
+    private boolean mScreenshotOnFailure;
+
+    public FailureListener(ITestInvocationListener listener, ITestDevice device,
+            boolean bugReportOnFailure, boolean logcatOnFailure, boolean screenshotOnFailure) {
+        super(listener);
+        mDevice = device;
+        mBugReportOnFailure = bugReportOnFailure;
+        mLogcatOnFailure = logcatOnFailure;
+        mScreenshotOnFailure = screenshotOnFailure;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testFailed(TestIdentifier test, String trace) {
+        super.testFailed(test, trace);
+        CLog.i("FailureListener.testFailed %s %b %b %b", test.toString(), mBugReportOnFailure, mLogcatOnFailure, mScreenshotOnFailure);
+        if (mBugReportOnFailure) {
+           InputStreamSource bugSource = mDevice.getBugreport();
+           super.testLog(String.format("%s-bugreport", test.toString()), LogDataType.BUGREPORT,
+                   bugSource);
+           bugSource.cancel();
+        }
+        if (mLogcatOnFailure) {
+            // sleep 2s to ensure test failure stack trace makes it into logcat capture
+            RunUtil.getDefault().sleep(2 * 1000);
+            InputStreamSource logSource = mDevice.getLogcat(MAX_LOGCAT_BYTES);
+            super.testLog(String.format("%s-logcat", test.toString()), LogDataType.LOGCAT,
+                    logSource);
+            logSource.cancel();
+        }
+        if (mScreenshotOnFailure) {
+            try {
+                InputStreamSource screenSource = mDevice.getScreenshot();
+                super.testLog(String.format("%s-screenshot", test.toString()), LogDataType.PNG,
+                        screenSource);
+                screenSource.cancel();
+            } catch (DeviceNotAvailableException e) {
+                CLog.e(e);
+                CLog.e("Device %s became unavailable while capturing screenshot",
+                        mDevice.getSerialNumber());
+            }
+        }
+    }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
new file mode 100644
index 0000000..931ed1f
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IRuntimeHintProvider;
+
+import java.util.Set;
+
+/**
+ * Container for Compatibility test info.
+ */
+public interface IModuleDef extends Comparable<IModuleDef>, IBuildReceiver, IDeviceTest,
+        IRemoteTest, IRuntimeHintProvider {
+
+    /**
+     * @return The name of this module.
+     */
+    String getName();
+
+    /**
+     * @return a {@link String} to uniquely identify this module.
+     */
+    String getId();
+
+    /**
+     * @return the abi of this test module.
+     */
+    IAbi getAbi();
+
+    /**
+     * @return the {@link Set} of tokens a device must have in order to run this module.
+     */
+    Set<String> getTokens();
+
+    /**
+     * @return the {@link IRemoteTest} that runs the tests.
+     */
+    IRemoteTest getTest();
+
+    /**
+     * Adds a filter to include a specific test
+     *
+     * @param name the name of the test. Can be <package>, <package>.<class>,
+     * <package>.<class>#<method> or <native_name>
+     */
+    void addIncludeFilter(String name);
+
+    /**
+     * Adds a filter to exclude a specific test
+     *
+     * @param name the name of the test. Can be <package>, <package>.<class>,
+     * <package>.<class>#<method> or <native_name>
+     */
+    void addExcludeFilter(String name);
+
+    /**
+     * Runs the module's precondition checks and setup tasks.
+     */
+    void prepare(boolean skipPrep) throws DeviceNotAvailableException;
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
new file mode 100644
index 0000000..24e1dec
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.IAbi;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Interface for accessing tests from the Compatibility repository.
+ */
+public interface IModuleRepo {
+
+    /**
+     * @return true if this repository has been initialized.
+     */
+    boolean isInitialized();
+
+    /**
+     * Initializes the repository.
+     */
+    void initialize(int shards, File testsDir, Set<IAbi> abis, List<String> deviceTokens,
+            List<String> testArgs, List<String> moduleArgs, List<String> mIncludeFilters,
+            List<String> mExcludeFilters, IBuildInfo buildInfo);
+
+    /**
+     * @return a {@link Map} of all modules to run on the device referenced by the given serial.
+     */
+    List<IModuleDef> getModules(String serial);
+
+    /**
+     * @return the number of shards this repo is initialized for.
+     */
+    int getNumberOfShards();
+
+    /**
+     * @return the maximum number of modules a shard will run.
+     */
+    int getModulesPerShard();
+
+    /**
+     * @return the {@link Map} of device serials to tokens.
+     */
+    Map<String, Set<String>> getDeviceTokens();
+
+    /**
+     * @return the {@link Set} of device serials that have taken their workload.
+     */
+    Set<String> getSerials();
+
+    /**
+     * @return the small modules that don't have tokens but have not been assigned to a device.
+     */
+    List<IModuleDef> getSmallModules();
+
+    /**
+     * @return the medium modules that don't have tokens but have not been assigned to a device.
+     */
+    List<IModuleDef> getMediumModules();
+
+    /**
+     * @return the large modules that don't have tokens but have not been assigned to a device.
+     */
+    List<IModuleDef> getLargeModules();
+
+    /**
+     * @return the modules which have token and have not been assigned to a device.
+     */
+    List<IModuleDef> getTokenModules();
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
new file mode 100644
index 0000000..ba4c6c3
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.Option.Importance;
+import com.android.tradefed.testtype.HostTest;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IRuntimeHintProvider;
+import com.android.tradefed.util.TimeVal;
+
+import junit.framework.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Test runner for host-side JUnit tests.
+ */
+public class JarHostTest extends HostTest implements IAbiReceiver, IBuildReceiver,
+        IRuntimeHintProvider {
+
+    @Option(name="jar", description="The jars containing the JUnit test class to run.",
+            importance = Importance.IF_UNSET)
+    private Set<String> mJars = new HashSet<>();
+
+    @Option(name = "runtime-hint",
+            isTimeVal = true,
+            description="The hint about the test's runtime.")
+    private long mRuntimeHint = 60000;// 1 minute
+
+    private IAbi mAbi;
+    private IBuildInfo mBuild;
+    private CompatibilityBuildHelper mHelper;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo build) {
+        mBuild = build;
+        mHelper = new CompatibilityBuildHelper(build);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long getRuntimeHint() {
+        return mRuntimeHint;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected List<Class<?>> getClasses() throws IllegalArgumentException  {
+        List<Class<?>> classes = super.getClasses();
+        for (String jarName : mJars) {
+            JarFile jarFile = null;
+            try {
+                File file = new File(mHelper.getTestsDir(), jarName);
+                jarFile = new JarFile(file);
+                Enumeration<JarEntry> e = jarFile.entries();
+                URL[] urls = {
+                        new URL(String.format("jar:file:%s!/", file.getAbsolutePath()))
+                };
+                URLClassLoader cl = URLClassLoader.newInstance(urls);
+
+                while (e.hasMoreElements()) {
+                    JarEntry je = e.nextElement();
+                    if (je.isDirectory() || !je.getName().endsWith(".class")
+                            || je.getName().contains("$")) {
+                        continue;
+                    }
+                    String className = getClassName(je.getName());
+                    try {
+                        Class<?> cls = cl.loadClass(className);
+                        int modifiers = cls.getModifiers();
+                        if ((IRemoteTest.class.isAssignableFrom(cls)
+                                || Test.class.isAssignableFrom(cls))
+                                && !Modifier.isStatic(modifiers)
+                                && !Modifier.isPrivate(modifiers)
+                                && !Modifier.isProtected(modifiers)
+                                && !Modifier.isInterface(modifiers)
+                                && !Modifier.isAbstract(modifiers)) {
+                            classes.add(cls);
+                        }
+                    } catch (ClassNotFoundException cnfe) {
+                        throw new IllegalArgumentException(
+                                String.format("Cannot find test class %s", className));
+                    }
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            } finally {
+                if (jarFile != null) {
+                    try {
+                        jarFile.close();
+                    } catch (IOException e) {
+                        // Ignored
+                    }
+                }
+            }
+        }
+        return classes;
+    }
+
+    private static String getClassName(String name) {
+        // -6 because of .class
+        return name.substring(0, name.length() - 6).replace('/', '.');
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Object loadObject(Class<?> classObj) throws IllegalArgumentException {
+        Object object = super.loadObject(classObj);
+        if (object instanceof IAbiReceiver) {
+            ((IAbiReceiver) object).setAbi(mAbi);
+        }
+        if (object instanceof IBuildReceiver) {
+            ((IBuildReceiver) object).setBuild(mBuild);
+        }
+        return object;
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
new file mode 100644
index 0000000..e24828d
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.compatibility.common.tradefed.result.IModuleListener;
+import com.android.compatibility.common.tradefed.result.ModuleListener;
+import com.android.compatibility.common.tradefed.targetprep.PreconditionPreparer;
+import com.android.compatibility.common.tradefed.targetprep.TokenRequirement;
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetCleaner;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IRuntimeHintProvider;
+import com.android.tradefed.testtype.ITestFilterReceiver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Container for Compatibility test module info.
+ */
+public class ModuleDef implements IModuleDef {
+
+    private final String mId;
+    private final String mName;
+    private final IAbi mAbi;
+    private final Set<String> mTokens = new HashSet<>();
+    private IRemoteTest mTest = null;
+    private List<ITargetPreparer> mPreconditions = new ArrayList<>();
+    private List<ITargetPreparer> mPreparers = new ArrayList<>();
+    private List<ITargetCleaner> mCleaners = new ArrayList<>();
+    private IBuildInfo mBuild;
+    private ITestDevice mDevice;
+    private List<String> mIncludeFilters = new ArrayList<>();
+    private List<String> mExcludeFilters = new ArrayList<>();
+
+    public ModuleDef(String name, IAbi abi, IRemoteTest test,
+            List<ITargetPreparer> preparers) {
+        mId = AbiUtils.createId(abi.getName(), name);
+        mName = name;
+        mAbi = abi;
+        mTest = test;
+        for (ITargetPreparer preparer : preparers) {
+            // Separate preconditions from target preparers.
+            if (preparer instanceof PreconditionPreparer) {
+                mPreconditions.add(preparer);
+            } else if (preparer instanceof TokenRequirement) {
+                mTokens.addAll(((TokenRequirement) preparer).getTokens());
+            } else {
+                mPreparers.add(preparer);
+            }
+            if (preparer instanceof ITargetCleaner) {
+                mCleaners.add((ITargetCleaner) preparer);
+            }
+        }
+        // Reverse cleaner order
+        Collections.reverse(mCleaners);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        return mId;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getId() {
+        return mId;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IAbi getAbi() {
+        return mAbi;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Set<String> getTokens() {
+        return mTokens;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long getRuntimeHint() {
+        if (mTest instanceof IRuntimeHintProvider) {
+            return ((IRuntimeHintProvider) mTest).getRuntimeHint();
+        }
+        return TimeUnit.MINUTES.toMillis(1); // Default 1 minute.
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IRemoteTest getTest() {
+        return mTest;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addIncludeFilter(String filter) {
+        mIncludeFilters.add(filter);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addExcludeFilter(String filter) {
+        mExcludeFilters.add(filter);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int compareTo(IModuleDef moduleDef) {
+        return getName().compareTo(moduleDef.getName());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo build) {
+        mBuild = build;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ITestDevice getDevice() {
+        return mDevice;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDevice(ITestDevice device) {
+        mDevice = device;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+        IModuleListener moduleListener = new ModuleListener(this, listener);
+
+        // Setup
+        for (ITargetPreparer preparer : mPreparers) {
+            CLog.d("Preparer: %s", preparer.getClass().getSimpleName());
+            if (preparer instanceof IAbiReceiver) {
+                ((IAbiReceiver) preparer).setAbi(mAbi);
+            }
+            try {
+                preparer.setUp(mDevice, mBuild);
+            } catch (BuildError e) {
+                // This should only happen for flashing new build
+                CLog.e("Unexpected BuildError from precondition: %s",
+                        preparer.getClass().getCanonicalName());
+            } catch (TargetSetupError e) {
+                // log precondition class then rethrow & let caller handle
+                CLog.e("TargetSetupError in precondition: %s",
+                        preparer.getClass().getCanonicalName());
+                throw new RuntimeException(e);
+            }
+        }
+
+
+        CLog.d("Test: %s", mTest.getClass().getSimpleName());
+        if (mTest instanceof IAbiReceiver) {
+            ((IAbiReceiver) mTest).setAbi(mAbi);
+        }
+        if (mTest instanceof IBuildReceiver) {
+            ((IBuildReceiver) mTest).setBuild(mBuild);
+        }
+        if (mTest instanceof IDeviceTest) {
+            ((IDeviceTest) mTest).setDevice(mDevice);
+        }
+        if (mTest instanceof ITestFilterReceiver) {
+            ((ITestFilterReceiver) mTest).addAllIncludeFilters(mIncludeFilters);
+            ((ITestFilterReceiver) mTest).addAllExcludeFilters(mExcludeFilters);
+        }
+        mTest.run(moduleListener);
+
+        // Tear down
+        for (ITargetCleaner cleaner : mCleaners) {
+            CLog.d("Cleaner: %s", cleaner.getClass().getSimpleName());
+            cleaner.tearDown(mDevice, mBuild, null);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void prepare(boolean skipPrep) throws DeviceNotAvailableException {
+        for (ITargetPreparer preparer : mPreconditions) {
+            CLog.d("Preparer: %s", preparer.getClass().getSimpleName());
+            if (preparer instanceof IAbiReceiver) {
+                ((IAbiReceiver) preparer).setAbi(mAbi);
+            }
+            setOption(preparer, CompatibilityTest.SKIP_PRECONDITIONS_OPTION,
+                    Boolean.toString(skipPrep));
+            try {
+                preparer.setUp(mDevice, mBuild);
+            } catch (BuildError e) {
+                // This should only happen for flashing new build
+                CLog.e("Unexpected BuildError from precondition: %s",
+                        preparer.getClass().getCanonicalName());
+            } catch (TargetSetupError e) {
+                // log precondition class then rethrow & let caller handle
+                CLog.e("TargetSetupError in precondition: %s",
+                        preparer.getClass().getCanonicalName());
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    private void setOption(Object target, String option, String value) {
+        try {
+            OptionSetter setter = new OptionSetter(target);
+            setter.setOptionValue(option, value);
+        } catch (ConfigurationException e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
new file mode 100644
index 0000000..5b6606c
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.compatibility.common.util.TestFilter;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.ConfigurationFactory;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.config.IConfigurationFactory;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.util.TimeUtil;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Retrieves Compatibility test module definitions from the repository.
+ */
+public class ModuleRepo implements IModuleRepo {
+
+    private static final String CONFIG_EXT = ".config";
+    private static final long SMALL_TEST = TimeUnit.MINUTES.toMillis(2); // Small tests < 2mins
+    private static final long MEDIUM_TEST = TimeUnit.MINUTES.toMillis(10); // Medium tests < 10mins
+
+    static IModuleRepo sInstance;
+
+    private int mShards;
+    private int mModulesPerShard;
+    private int mSmallModulesPerShard;
+    private int mMediumModulesPerShard;
+    private int mLargeModulesPerShard;
+    private int mModuleCount = 0;
+    private Set<String> mSerials = new HashSet<>();
+    private Map<String, Set<String>> mDeviceTokens = new HashMap<>();
+    private Map<String, Map<String, String>> mTestArgs = new HashMap<>();
+    private Map<String, Map<String, String>> mModuleArgs = new HashMap<>();
+    private boolean mIncludeAll;
+    private Map<String, List<TestFilter>> mIncludeFilters = new HashMap<>();
+    private Map<String, List<TestFilter>> mExcludeFilters = new HashMap<>();
+    private IConfigurationFactory mConfigFactory = ConfigurationFactory.getInstance();
+
+    private volatile boolean mInitialized = false;
+
+    // Holds all the small tests waiting to be run.
+    private List<IModuleDef> mSmallModules = new ArrayList<>();
+    // Holds all the medium tests waiting to be run.
+    private List<IModuleDef> mMediumModules = new ArrayList<>();
+    // Holds all the large tests waiting to be run.
+    private List<IModuleDef> mLargeModules = new ArrayList<>();
+    // Holds all the tests with tokens waiting to be run. Meaning the DUT must have a specific token.
+    private List<IModuleDef> mTokenModules = new ArrayList<>();
+
+    public static IModuleRepo getInstance() {
+        if (sInstance == null) {
+            sInstance = new ModuleRepo();
+        }
+        return sInstance;
+    }
+
+    public static void tearDown() {
+        sInstance = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getNumberOfShards() {
+        return mShards;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getModulesPerShard() {
+        return mModulesPerShard;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Map<String, Set<String>> getDeviceTokens() {
+        return mDeviceTokens;
+    }
+
+    /**
+     * A {@link FilenameFilter} to find all modules in a directory who match the given pattern.
+     */
+    public static class NameFilter implements FilenameFilter {
+
+        private String mPattern;
+
+        public NameFilter(String pattern) {
+            mPattern = pattern;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean accept(File dir, String name) {
+            return name.contains(mPattern) && name.endsWith(CONFIG_EXT);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Set<String> getSerials() {
+        return mSerials;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<IModuleDef> getSmallModules() {
+        return mSmallModules;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<IModuleDef> getMediumModules() {
+        return mMediumModules;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<IModuleDef> getLargeModules() {
+        return mLargeModules;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<IModuleDef> getTokenModules() {
+        return mTokenModules;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isInitialized() {
+        return mInitialized;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void initialize(int shards, File testsDir, Set<IAbi> abis, List<String> deviceTokens,
+            List<String> testArgs, List<String> moduleArgs, List<String> includeFilters,
+            List<String> excludeFilters, IBuildInfo buildInfo) {
+        mInitialized = true;
+        mShards = shards;
+        for (String line : deviceTokens) {
+            String[] parts = line.split(":");
+            if (parts.length == 2) {
+                String key = parts[0];
+                String value = parts[1];
+                Set<String> list = mDeviceTokens.get(key);
+                if (list == null) {
+                    list = new HashSet<>();
+                    mDeviceTokens.put(key, list);
+                }
+                list.add(value);
+            } else {
+                throw new IllegalArgumentException(
+                        String.format("Could not parse device token: %s", line));
+            }
+        }
+        putArgs(testArgs, mTestArgs);
+        putArgs(moduleArgs, mModuleArgs);
+        mIncludeAll = includeFilters.isEmpty();
+        // Include all the inclusions
+        addFilters(includeFilters, mIncludeFilters, abis);
+        // Exclude all the exclusions
+        addFilters(excludeFilters, mExcludeFilters, abis);
+
+        File[] configFiles = testsDir.listFiles(new ConfigFilter());
+        for (File configFile : configFiles) {
+            final String name = configFile.getName().replace(CONFIG_EXT, "");
+            final String[] pathArg = new String[] { configFile.getAbsolutePath() };
+            try {
+                // Invokes parser to process the test module config file
+                // Need to generate a different config for each ABI as we cannot guarantee the
+                // configs are idempotent. This however means we parse the same file multiple times
+                for (IAbi abi : abis) {
+                    IConfiguration config = mConfigFactory.createConfigurationFromArgs(pathArg);
+                    String id = AbiUtils.createId(abi.getName(), name);
+                    {
+                        Map<String, String> args = new HashMap<>();
+                        if (mModuleArgs.containsKey(name)) {
+                            args.putAll(mModuleArgs.get(name));
+                        }
+                        if (mModuleArgs.containsKey(id)) {
+                            args.putAll(mModuleArgs.get(id));
+                        }
+                        if (args != null && args.size() > 0) {
+                            for (Entry<String, String> entry : args.entrySet()) {
+                                config.injectOptionValue(entry.getKey(), entry.getValue());
+                            }
+                        }
+                    }
+                    List<IRemoteTest> tests = config.getTests();
+                    for (IRemoteTest test : tests) {
+                        String className = test.getClass().getName();
+                        Map<String, String> args = new HashMap<>();
+                        if (mTestArgs.containsKey(className)) {
+                            args.putAll(mTestArgs.get(className));
+                        }
+                        if (args != null && args.size() > 0) {
+                            for (Entry<String, String> entry : args.entrySet()) {
+                                config.injectOptionValue(entry.getKey(), entry.getValue());
+                            }
+                        }
+                    }
+                    List<IRemoteTest> shardedTests = tests;
+                    if (mShards > 1) {
+                         shardedTests = splitShardableTests(tests, buildInfo);
+                    }
+                    for (IRemoteTest test : shardedTests) {
+                        if (test instanceof IBuildReceiver) {
+                            ((IBuildReceiver)test).setBuild(buildInfo);
+                        }
+                        addModuleDef(name, abi, test, pathArg);
+                    }
+                }
+            } catch (ConfigurationException e) {
+                throw new RuntimeException(String.format("error parsing config file: %s",
+                        configFile.getName()), e);
+            }
+        }
+        mModulesPerShard = mModuleCount / shards;
+        if (mModuleCount % shards != 0) {
+            mModulesPerShard++; // Round up
+        }
+        mSmallModulesPerShard = mSmallModules.size() / shards;
+        mMediumModulesPerShard = mMediumModules.size() / shards;
+        mLargeModulesPerShard = mLargeModules.size() / shards;
+    }
+
+    private static List<IRemoteTest> splitShardableTests(List<IRemoteTest> tests,
+            IBuildInfo buildInfo) {
+        ArrayList<IRemoteTest> shardedList = new ArrayList<>(tests.size());
+        for (IRemoteTest test : tests) {
+            if (test instanceof IShardableTest) {
+                if (test instanceof IBuildReceiver) {
+                    ((IBuildReceiver)test).setBuild(buildInfo);
+                }
+                shardedList.addAll(((IShardableTest)test).split());
+            } else {
+                shardedList.add(test);
+            }
+        }
+        return shardedList;
+    }
+
+    private static void addFilters(List<String> stringFilters,
+            Map<String, List<TestFilter>> filters, Set<IAbi> abis) {
+        for (String filterString : stringFilters) {
+            TestFilter filter = TestFilter.createFrom(filterString);
+            String abi = filter.getAbi();
+            if (abi == null) {
+                for (IAbi a : abis) {
+                    addFilter(a.getName(), filter, filters);
+                }
+            } else {
+                addFilter(abi, filter, filters);
+            }
+        }
+    }
+
+    private static void addFilter(String abi, TestFilter filter,
+            Map<String, List<TestFilter>> filters) {
+        getFilter(filters, AbiUtils.createId(abi, filter.getName())).add(filter);
+    }
+
+    private static List<TestFilter> getFilter(Map<String, List<TestFilter>> filters, String id) {
+        List<TestFilter> fs = filters.get(id);
+        if (fs == null) {
+            fs = new ArrayList<>();
+            filters.put(id, fs);
+        }
+        return fs;
+    }
+
+    private void addModuleDef(String name, IAbi abi, IRemoteTest test,
+            String[] configPaths) throws ConfigurationException {
+        // Invokes parser to process the test module config file
+        IConfiguration config = mConfigFactory.createConfigurationFromArgs(configPaths);
+        addModuleDef(new ModuleDef(name, abi, test, config.getTargetPreparers()));
+    }
+
+    private void addModuleDef(IModuleDef moduleDef) {
+        String id = moduleDef.getId();
+        boolean includeModule = mIncludeAll;
+        for (TestFilter include : getFilter(mIncludeFilters, id)) {
+            String test = include.getTest();
+            if (test != null) {
+                // We're including a subset of tests
+                moduleDef.addIncludeFilter(test);
+            }
+            includeModule = true;
+        }
+        for (TestFilter exclude : getFilter(mExcludeFilters, id)) {
+            String test = exclude.getTest();
+            if (test != null) {
+                // Excluding a subset of tests, so keep module but give filter
+                moduleDef.addExcludeFilter(test);
+            } else {
+                // Excluding all tests in the module so just remove the whole thing
+                includeModule = false;
+            }
+        }
+        if (includeModule) {
+            Set<String> tokens = moduleDef.getTokens();
+            if (tokens != null && !tokens.isEmpty()) {
+                mTokenModules.add(moduleDef);
+            } else if (moduleDef.getRuntimeHint() < SMALL_TEST) {
+                mSmallModules.add(moduleDef);
+            } else if (moduleDef.getRuntimeHint() < MEDIUM_TEST) {
+                mMediumModules.add(moduleDef);
+            } else {
+                mLargeModules.add(moduleDef);
+            }
+            mModuleCount++;
+        }
+    }
+
+    /**
+     * A {@link FilenameFilter} to find all the config files in a directory.
+     */
+    public static class ConfigFilter implements FilenameFilter {
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean accept(File dir, String name) {
+            return name.endsWith(CONFIG_EXT);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public synchronized List<IModuleDef> getModules(String serial) {
+        Set<String> tokens = mDeviceTokens.get(serial);
+        List<IModuleDef> modules = new ArrayList<>(mModulesPerShard);
+        getModulesWithTokens(tokens, modules);
+        getModules(modules);
+        long estimatedTime = 0;
+        for (IModuleDef def : modules) {
+            estimatedTime += def.getRuntimeHint();
+        }
+        mSerials.add(serial);
+        if (mSerials.size() == mShards) {
+            // All shards have been given their workload.
+            if (!mTokenModules.isEmpty()) {
+                Set<String> deviceTokens = mDeviceTokens.keySet();
+                Set<String> moduleTokens = new HashSet<>();
+                for (IModuleDef module : mTokenModules) {
+                    moduleTokens.addAll(module.getTokens());
+                }
+                StringBuilder sb = new StringBuilder("Not all modules could be scheduled.");
+                for (String token : moduleTokens) {
+                    if (!deviceTokens.contains(token)) {
+                        sb.append("\nNo devices found with token: ");
+                        sb.append(token);
+                    }
+                }
+                sb.append("\nDeclare device tokens with \"--device-token <serial>:<token>\"");
+                throw new IllegalArgumentException(sb.toString());
+            }
+            if (!mLargeModules.isEmpty()) {
+                throw new IllegalArgumentException("Couldn't schedule: " + mLargeModules);
+            }
+            if (!mMediumModules.isEmpty()) {
+                throw new IllegalArgumentException("Couldn't schedule: " + mMediumModules);
+            }
+            if (!mSmallModules.isEmpty()) {
+                throw new IllegalArgumentException("Couldn't schedule: " + mSmallModules);
+            }
+        }
+        Collections.sort(modules, new RuntimeHintComparator());
+        CLog.logAndDisplay(LogLevel.INFO, String.format(
+                "%s running %s modules, expected to complete in %s",
+                serial, modules.size(), TimeUtil.formatElapsedTime(estimatedTime)));
+        return modules;
+    }
+
+    /**
+     * Iterates through the remaining tests that require tokens and if the device has all the
+     * required tokens it will queue that module to run on that device, else the module gets put
+     * back into the list.
+     */
+    private void getModulesWithTokens(Set<String> tokens, List<IModuleDef> modules) {
+        if (tokens != null) {
+            List<IModuleDef> copy = mTokenModules;
+            mTokenModules = new ArrayList<>();
+            for (IModuleDef module : copy) {
+                // If a device has all the tokens required by the module then it can run it.
+                if (tokens.containsAll(module.getTokens())) {
+                    modules.add(module);
+                } else {
+                    mTokenModules.add(module);
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds count modules that do not require tokens, to run on a device.
+     */
+    private void getModules(List<IModuleDef> modules) {
+        // Take the normal share of modules unless the device already has token modules.
+        takeModule(mSmallModules, modules, mSmallModulesPerShard - modules.size());
+        takeModule(mMediumModules, modules, mMediumModulesPerShard);
+        takeModule(mLargeModules, modules, mLargeModulesPerShard);
+        // If one bucket runs out, take from any of the others.
+        boolean success = true;
+        while (success && modules.size() < mModulesPerShard) {
+            // Take modules from the buckets until it has enough, or there are no more modules.
+            success = takeModule(mSmallModules, modules, 1)
+                    || takeModule(mMediumModules, modules, 1)
+                    || takeModule(mLargeModules, modules, 1);
+        }
+    }
+
+    /**
+     * Takes count modules from the first list and move it to the second.
+     */
+    private static boolean takeModule(
+            List<IModuleDef> source, List<IModuleDef> destination, int count) {
+        if (source.isEmpty()) {
+            return false;
+        }
+        if (count > source.size()) {
+            count = source.size();
+        }
+        for (int i = 0; i < count; i++) {
+            destination.add(source.remove(source.size() - 1));// Take from the end of the arraylist.
+        }
+        return true;
+    }
+
+    /**
+     * @return the {@link List} of modules whose name contains the given pattern.
+     */
+    public static List<String> getModuleNamesMatching(File directory, String pattern) {
+        String[] names = directory.list(new NameFilter(pattern));
+        List<String> modules = new ArrayList<String>(names.length);
+        for (String name : names) {
+            int index = name.indexOf(CONFIG_EXT);
+            if (index > 0) {
+                modules.add(name.substring(0, index));
+            }
+        }
+        return modules;
+    }
+
+    private static void putArgs(List<String> args, Map<String, Map<String, String>> argsMap) {
+        for (String arg : args) {
+            String[] parts = arg.split(":");
+            String target = parts[0];
+            String key = parts[1];
+            String value = parts[2];
+            Map<String, String> map = argsMap.get(target);
+            if (map == null) {
+                map = new HashMap<>();
+                argsMap.put(target, map);
+            }
+            map.put(key, value);
+        }
+    }
+
+    private static class RuntimeHintComparator implements Comparator<IModuleDef> {
+
+        @Override
+        public int compare(IModuleDef def1, IModuleDef def2) {
+            return (int) Math.signum(def2.getRuntimeHint() - def1.getRuntimeHint());
+        }
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/NoOpTestInvocationListener.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/NoOpTestInvocationListener.java
new file mode 100644
index 0000000..06f493d
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/NoOpTestInvocationListener.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.util;
+
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.ddmlib.testrunner.ITestRunListener;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.result.InputStreamSource;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.TestSummary;
+
+import java.util.Map;
+
+/**
+ * Implementation of ITestInvocationListener that does nothing or returns null for all methods.
+ * Extend this class to implement some, but not all methods of ITestInvocationListener.
+ */
+public class NoOpTestInvocationListener implements ITestInvocationListener {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void invocationStarted(IBuildInfo buildInfo) {}
+
+     /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void invocationEnded(long elapsedTime) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void invocationFailed(Throwable cause) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public TestSummary getSummary() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunStarted(String runName, int testCount) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testStarted(TestIdentifier test) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testFailed(TestIdentifier test, String trace) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testAssumptionFailure(TestIdentifier test, String trace) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testIgnored(TestIdentifier test) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunFailed(String errorMessage) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunStopped(long elapsedTime) {}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testRunEnded(long elapsedTime, Map<String, String> runMetrics) {}
+
+}
diff --git a/common/host-side/tradefed/tests/Android.mk b/common/host-side/tradefed/tests/Android.mk
new file mode 100644
index 0000000..6d4a6cb
--- /dev/null
+++ b/common/host-side/tradefed/tests/Android.mk
@@ -0,0 +1,45 @@
+# Copyright (C) 2015 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.
+
+# Make a mock compatibility suite to test
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
+LOCAL_JAVA_RESOURCE_DIRS := ../res
+
+LOCAL_SUITE_BUILD_NUMBER := 2
+LOCAL_SUITE_NAME := TESTS
+LOCAL_SUITE_FULLNAME := "Compatibility Tests"
+LOCAL_SUITE_VERSION := 1
+
+LOCAL_MODULE := compatibility-mock-tradefed
+
+include $(BUILD_COMPATIBILITY_SUITE)
+
+# Make the tests
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := compatibility-tradefed-tests
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := easymock
+
+LOCAL_JAVA_LIBRARIES := tradefed-prebuilt compatibility-mock-tradefed junit compatibility-host-util
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/tradefed/tests/run_tests.sh b/common/host-side/tradefed/tests/run_tests.sh
new file mode 100755
index 0000000..1d1940d
--- /dev/null
+++ b/common/host-side/tradefed/tests/run_tests.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# Copyright (C) 2015 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.
+
+CTS_DIR=$(dirname ${0})/../../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+    compatibility-common-util-hostsidelib\
+    compatibility-common-util-tests\
+    compatibility-host-util\
+    compatibility-host-util-tests\
+    compatibility-mock-tradefed\
+    compatibility-tradefed-tests"
+
+run_tests "com.android.compatibility.common.tradefed.UnitTests" "${JARS}" "${@}"
+
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/TradefedTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/TradefedTest.java
deleted file mode 100644
index ab19369..0000000
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/TradefedTest.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.compatibility.common.tradefed;
-
-import junit.framework.TestCase;
-
-public class TradefedTest extends TestCase {
-
-    // TODO(stuartscott): Add tests when there is something to test.
-
-}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
new file mode 100644
index 0000000..318960c
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelperTest;
+import com.android.compatibility.common.tradefed.command.CompatibilityConsoleTest;
+import com.android.compatibility.common.tradefed.result.ResultReporterTest;
+import com.android.compatibility.common.tradefed.targetprep.PropertyCheckTest;
+import com.android.compatibility.common.tradefed.targetprep.SettingsPreparerTest;
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTestTest;
+import com.android.compatibility.common.tradefed.testtype.ModuleDefTest;
+import com.android.compatibility.common.tradefed.testtype.ModuleRepoTest;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * A test suite for all compatibility tradefed unit tests.
+ * <p/>
+ * All tests listed here should be self-contained, and do not require any external dependencies.
+ */
+public class UnitTests extends TestSuite {
+
+    public UnitTests() {
+        super();
+        addTestSuite(CompatibilityBuildHelperTest.class);
+        addTestSuite(CompatibilityConsoleTest.class);
+        addTestSuite(ResultReporterTest.class);
+        addTestSuite(CompatibilityTestTest.class);
+        addTestSuite(ModuleDefTest.class);
+        addTestSuite(ModuleRepoTest.class);
+        addTestSuite(PropertyCheckTest.class);
+        addTestSuite(SettingsPreparerTest.class);
+    }
+
+    public static Test suite() {
+        return new UnitTests();
+    }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
new file mode 100644
index 0000000..55d15dd
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.build;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.util.FileUtil;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+public class CompatibilityBuildHelperTest extends TestCase {
+
+    private static final String ROOT_PROPERTY = "TESTS_ROOT";
+    private static final String BUILD_NUMBER = "2";
+    private static final String SUITE_NAME = "TESTS";
+    private static final String SUITE_FULL_NAME = "Compatibility Tests";
+    private static final String SUITE_VERSION = "1";
+    private static final String SUITE_PLAN = "cts";
+    private static final String DYNAMIC_CONFIG_URL = "";
+    private static final String ROOT_DIR_NAME = "root";
+    private static final String BASE_DIR_NAME = "android-tests";
+    private static final String TESTCASES = "testcases";
+
+    private File mRoot = null;
+    private File mBase = null;
+    private File mTests = null;
+    private IBuildInfo mBuild;
+    private CompatibilityBuildHelper mHelper;
+
+    @Override
+    public void setUp() throws Exception {
+        mRoot = FileUtil.createTempDir(ROOT_DIR_NAME);
+        CompatibilityBuildProvider provider = new CompatibilityBuildProvider();
+        mBuild = provider.getBuild();
+        mHelper = new CompatibilityBuildHelper(mBuild);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        setProperty(null);
+        FileUtil.recursiveDelete(mRoot);
+        mRoot = null;
+        mBase = null;
+        mTests = null;
+    }
+
+    private void createDirStructure() {
+        mBase = new File(mRoot, BASE_DIR_NAME);
+        mBase.mkdirs();
+        mTests = new File(mBase, TESTCASES);
+        mTests.mkdirs();
+    }
+
+    public void testSuiteInfoLoad() throws Exception {
+        setProperty(mRoot.getAbsolutePath());
+        mHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL);
+        assertEquals("Incorrect suite build number", BUILD_NUMBER, mHelper.getSuiteBuild());
+        assertEquals("Incorrect suite name", SUITE_NAME, mHelper.getSuiteName());
+        assertEquals("Incorrect suite full name", SUITE_FULL_NAME, mHelper.getSuiteFullName());
+        assertEquals("Incorrect suite version", SUITE_VERSION, mHelper.getSuiteVersion());
+    }
+
+    public void testProperty() throws Exception {
+        setProperty(null);
+        CompatibilityBuildProvider provider = new CompatibilityBuildProvider();
+        CompatibilityBuildHelper helper = new CompatibilityBuildHelper(provider.getBuild());
+        try {
+            // Should fail with root unset
+            helper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL);
+            fail("Expected fail for unset root property");
+        } catch (IllegalArgumentException e) {
+            /* expected */
+        }
+        setProperty(mRoot.getAbsolutePath());
+        // Shouldn't fail with root set
+        helper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL);
+    }
+
+    public void testValidation() throws Exception {
+        setProperty(mRoot.getAbsolutePath());
+        mHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL);
+        try {
+            mHelper.getDir();
+            fail("Build helper validation succeeded on an invalid installation");
+        } catch (FileNotFoundException e) {
+            // Expected
+        }
+        createDirStructure();
+        try {
+            mHelper.getTestsDir();
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+            fail("Build helper validation failed on a valid installation");
+        }
+    }
+
+    public void testDirs() throws Exception {
+        setProperty(mRoot.getAbsolutePath());
+        mHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL);
+        createDirStructure();
+        assertNotNull(mRoot);
+        assertNotNull(mBuild);
+        assertNotNull(mHelper.getRootDir());
+        assertEquals("Incorrect root dir", mRoot.getAbsolutePath(),
+                mHelper.getRootDir().getAbsolutePath());
+        assertEquals("Incorrect base dir", mBase.getAbsolutePath(),
+                mHelper.getDir().getAbsolutePath());
+        assertEquals("Incorrect logs dir", new File(mBase, "logs").getAbsolutePath(),
+                mHelper.getLogsDir().getAbsolutePath());
+        assertEquals("Incorrect tests dir", mTests.getAbsolutePath(),
+                mHelper.getTestsDir().getAbsolutePath());
+        assertEquals("Incorrect results dir", new File(mBase, "results").getAbsolutePath(),
+                mHelper.getResultsDir().getAbsolutePath());
+    }
+
+    /**
+     * Sets the *_ROOT property of the build's installation location.
+     *
+     * @param value the value to set, or null to clear the property.
+     */
+    public static void setProperty(String value) {
+        if (value == null) {
+            System.clearProperty(ROOT_PROPERTY);
+        } else {
+            System.setProperty(ROOT_PROPERTY, value);
+        }
+    }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/command/CompatibilityConsoleTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/command/CompatibilityConsoleTest.java
new file mode 100644
index 0000000..55c1651
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/command/CompatibilityConsoleTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.command;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelperTest;
+
+import junit.framework.TestCase;
+
+public class CompatibilityConsoleTest extends TestCase {
+
+    @Override
+    public void setUp() throws Exception {
+        CompatibilityBuildHelperTest.setProperty("/tmp/foobar");
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        CompatibilityBuildHelperTest.setProperty(null);
+    }
+
+    public void testHelpExists() throws Exception {
+        CompatibilityConsole console = new CompatibilityConsole() {};
+        assertFalse("No help", console.getGenericHelpString(null).isEmpty());
+    }
+
+    public void testPromptExists() throws Exception {
+        CompatibilityConsole console = new CompatibilityConsole() {};
+        assertFalse("No prompt", console.getConsolePrompt().isEmpty());
+    }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
new file mode 100644
index 0000000..3fcf8b5
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.result;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.compatibility.common.util.ICaseResult;
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.IModuleResult;
+import com.android.compatibility.common.util.ITestResult;
+import com.android.compatibility.common.util.TestStatus;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.BuildInfo;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.util.FileUtil;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.HashMap;
+import java.util.List;
+
+public class ResultReporterTest extends TestCase {
+
+    private static final String ROOT_PROPERTY = "TESTS_ROOT";
+    private static final String BUILD_NUMBER = "2";
+    private static final String SUITE_PLAN = "cts";
+    private static final String DYNAMIC_CONFIG_URL = "";
+    private static final String ROOT_DIR_NAME = "root";
+    private static final String BASE_DIR_NAME = "android-tests";
+    private static final String TESTCASES = "testcases";
+    private static final String NAME = "ModuleName";
+    private static final String ABI = "mips64";
+    private static final String ID = AbiUtils.createId(ABI, NAME);
+    private static final String CLASS = "android.test.FoorBar";
+    private static final String METHOD_1 = "testBlah1";
+    private static final String METHOD_2 = "testBlah2";
+    private static final String METHOD_3 = "testBlah3";
+    private static final String TEST_1 = String.format("%s#%s", CLASS, METHOD_1);
+    private static final String TEST_2 = String.format("%s#%s", CLASS, METHOD_2);
+    private static final String TEST_3 = String.format("%s#%s", CLASS, METHOD_3);
+    private static final String STACK_TRACE = "Something small is not alright\n " +
+            "at four.big.insects.Marley.sing(Marley.java:10)";
+    private static final String RESULT_DIR = "result123";
+    private static final String[] FORMATTING_FILES = {
+        "compatibility_result.css",
+        "compatibility_result.xsd",
+        "compatibility_result.xsl",
+        "logo.png",
+        "newrule_green.png"};
+
+    private ResultReporter mReporter;
+    private IBuildInfo mBuildInfo;
+    private CompatibilityBuildHelper mBuildHelper;
+
+    private File mRoot = null;
+    private File mBase = null;
+    private File mTests = null;
+
+    @Override
+    public void setUp() throws Exception {
+        mReporter = new ResultReporter();
+        OptionSetter setter = new OptionSetter(mReporter);
+        setter.setOptionValue("quiet-output", "true");
+        mRoot = FileUtil.createTempDir(ROOT_DIR_NAME);
+        mBase = new File(mRoot, BASE_DIR_NAME);
+        mBase.mkdirs();
+        mTests = new File(mBase, TESTCASES);
+        mTests.mkdirs();
+        System.setProperty(ROOT_PROPERTY, mRoot.getAbsolutePath());
+        mBuildInfo = new BuildInfo(BUILD_NUMBER, "", "");
+        mBuildHelper = new CompatibilityBuildHelper(mBuildInfo);
+        mBuildHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mReporter = null;
+        FileUtil.recursiveDelete(mRoot);
+    }
+
+    public void testSetup() throws Exception {
+        mReporter.invocationStarted(mBuildInfo);
+        // Should have created a directory for the logs
+        File[] children = mBuildHelper.getLogsDir().listFiles();
+        assertTrue("Didn't create logs dir", children.length == 1 && children[0].isDirectory());
+        // Should have created a directory for the results
+        children = mBuildHelper.getResultsDir().listFiles();
+        assertTrue("Didn't create results dir", children.length == 1 && children[0].isDirectory());
+        mReporter.invocationEnded(10);
+        // Should have created a zip file
+        children = mBuildHelper.getResultsDir().listFiles(new FileFilter() {
+            @Override
+            public boolean accept(File pathname) {
+                return pathname.getName().endsWith(".zip");
+            }
+        });
+        assertTrue("Didn't create results zip",
+                children.length == 1 && children[0].isFile() && children[0].length() > 0);
+    }
+
+    public void testResultReporting() throws Exception {
+        mReporter.invocationStarted(mBuildInfo);
+        mReporter.testRunStarted(ID, 2);
+        TestIdentifier test1 = new TestIdentifier(CLASS, METHOD_1);
+        mReporter.testStarted(test1);
+        mReporter.testEnded(test1, new HashMap<String, String>());
+        TestIdentifier test2 = new TestIdentifier(CLASS, METHOD_2);
+        mReporter.testStarted(test2);
+        mReporter.testFailed(test2, STACK_TRACE);
+        TestIdentifier test3 = new TestIdentifier(CLASS, METHOD_3);
+        mReporter.testStarted(test3);
+        mReporter.testFailed(test3, STACK_TRACE);
+        mReporter.testRunEnded(10, new HashMap<String, String>());
+        mReporter.invocationEnded(10);
+        IInvocationResult result = mReporter.getResult();
+        assertEquals("Expected 1 pass", 1, result.countResults(TestStatus.PASS));
+        assertEquals("Expected 2 failures", 2, result.countResults(TestStatus.FAIL));
+        List<IModuleResult> modules = result.getModules();
+        assertEquals("Expected 1 module", 1, modules.size());
+        IModuleResult module = modules.get(0);
+        assertEquals("Incorrect ID", ID, module.getId());
+        List<ICaseResult> caseResults = module.getResults();
+        assertEquals("Expected 1 test case", 1, caseResults.size());
+        ICaseResult caseResult = caseResults.get(0);
+        List<ITestResult> testResults = caseResult.getResults();
+        assertEquals("Expected 3 tests", 3, testResults.size());
+        ITestResult result1 = caseResult.getResult(METHOD_1);
+        assertNotNull(String.format("Expected result for %s", TEST_1), result1);
+        assertEquals(String.format("Expected pass for %s", TEST_1), TestStatus.PASS,
+                result1.getResultStatus());
+        ITestResult result2 = caseResult.getResult(METHOD_2);
+        assertNotNull(String.format("Expected result for %s", TEST_2), result2);
+        assertEquals(String.format("Expected fail for %s", TEST_2), TestStatus.FAIL,
+                result2.getResultStatus());
+        ITestResult result3 = caseResult.getResult(METHOD_3);
+        assertNotNull(String.format("Expected result for %s", TEST_3), result3);
+        assertEquals(String.format("Expected fail for %s", TEST_3), TestStatus.FAIL,
+                result3.getResultStatus());
+    }
+
+    public void testCopyFormattingFiles() throws Exception {
+        File resultDir = new File(mBuildHelper.getResultsDir(), RESULT_DIR);
+        resultDir.mkdirs();
+        ResultReporter.copyFormattingFiles(resultDir);
+        for (String filename : FORMATTING_FILES) {
+            File file = new File(resultDir, filename);
+            assertTrue(String.format("%s (%s) was not created", filename, file.getAbsolutePath()),
+                    file.exists() && file.isFile() && file.length() > 0);
+        }
+    }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java
new file mode 100644
index 0000000..a309a47
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.tradefed.build.DeviceBuildInfo;
+import com.android.tradefed.build.IDeviceBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+
+public class PropertyCheckTest extends TestCase {
+
+    private PropertyCheck mPropertyCheck;
+    private IDeviceBuildInfo mMockBuildInfo;
+    private ITestDevice mMockDevice;
+    private OptionSetter mOptionSetter;
+
+    private static final String PROPERTY = "ro.mock.property";
+    private static final String ACTUAL_VALUE = "mock_actual_value";
+    private static final String BAD_VALUE = "mock_bad_value";
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mPropertyCheck = new PropertyCheck();
+        mMockDevice = EasyMock.createMock(ITestDevice.class);
+        mMockBuildInfo = new DeviceBuildInfo("0", "", "");
+        mOptionSetter = new OptionSetter(mPropertyCheck);
+        EasyMock.expect(mMockDevice.getProperty(PROPERTY)).andReturn(ACTUAL_VALUE).anyTimes();
+    }
+
+    public void testWarningMatch() throws Exception {
+        mOptionSetter.setOptionValue("property-name", PROPERTY);
+        mOptionSetter.setOptionValue("expected-value", ACTUAL_VALUE);
+        mOptionSetter.setOptionValue("throw-error", "false");
+        EasyMock.replay(mMockDevice);
+        mPropertyCheck.run(mMockDevice, mMockBuildInfo); // no warnings or errors
+    }
+
+    public void testWarningMismatch() throws Exception {
+        mOptionSetter.setOptionValue("property-name", PROPERTY);
+        mOptionSetter.setOptionValue("expected-value", BAD_VALUE);
+        mOptionSetter.setOptionValue("throw-error", "false");
+        EasyMock.replay(mMockDevice);
+        mPropertyCheck.run(mMockDevice, mMockBuildInfo); // should only print a warning
+    }
+
+    public void testErrorMatch() throws Exception {
+        mOptionSetter.setOptionValue("property-name", PROPERTY);
+        mOptionSetter.setOptionValue("expected-value", ACTUAL_VALUE);
+        mOptionSetter.setOptionValue("throw-error", "true");
+        EasyMock.replay(mMockDevice);
+        mPropertyCheck.run(mMockDevice, mMockBuildInfo); // no warnings or errors
+    }
+
+    public void testErrorMismatch() throws Exception {
+        mOptionSetter.setOptionValue("property-name", PROPERTY);
+        mOptionSetter.setOptionValue("expected-value", BAD_VALUE);
+        mOptionSetter.setOptionValue("throw-error", "true");
+        EasyMock.replay(mMockDevice);
+        try {
+            mPropertyCheck.run(mMockDevice, mMockBuildInfo); // expecting TargetSetupError
+            fail("TargetSetupError expected");
+        } catch (TargetSetupError e) {
+            // Expected
+        }
+    }
+
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java
new file mode 100644
index 0000000..739662e
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.tradefed.build.DeviceBuildInfo;
+import com.android.tradefed.build.BuildInfo;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+
+public class SettingsPreparerTest extends TestCase {
+
+    private SettingsPreparer mSettingsPreparer;
+    private IBuildInfo mMockBuildInfo;
+    private ITestDevice mMockDevice;
+    private OptionSetter mOptionSetter;
+
+    private static final String SHELL_CMD_GET = "settings get GLOBAL stay_on_while_plugged_in";
+    private static final String SHELL_CMD_PUT_7 = "settings put GLOBAL stay_on_while_plugged_in 7";
+    private static final String SHELL_CMD_PUT_8 = "settings put GLOBAL stay_on_while_plugged_in 8";
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mSettingsPreparer = new SettingsPreparer();
+        mMockDevice = EasyMock.createMock(ITestDevice.class);
+        mMockBuildInfo = new BuildInfo("0", "", "");
+        mOptionSetter = new OptionSetter(mSettingsPreparer);
+        mOptionSetter.setOptionValue("device-setting", "stay_on_while_plugged_in");
+        mOptionSetter.setOptionValue("setting-type", "global");
+    }
+
+    public void testCorrectOneExpected() throws Exception {
+        EasyMock.expect(mMockDevice.executeShellCommand(SHELL_CMD_GET)).andReturn("\n3\n").once();
+        mOptionSetter.setOptionValue("expected-values", "3");
+        EasyMock.replay(mMockDevice);
+        mSettingsPreparer.run(mMockDevice, mMockBuildInfo);
+    }
+
+    public void testCorrectManyExpected() throws Exception {
+        EasyMock.expect(mMockDevice.executeShellCommand(SHELL_CMD_GET)).andReturn("\n3\n").once();
+        mOptionSetter.setOptionValue("expected-values", "2");
+        mOptionSetter.setOptionValue("expected-values", "3");
+        mOptionSetter.setOptionValue("expected-values", "6");
+        mOptionSetter.setOptionValue("expected-values", "7");
+        EasyMock.replay(mMockDevice);
+        mSettingsPreparer.run(mMockDevice, mMockBuildInfo);
+    }
+
+    public void testIncorrectOneExpected() throws Exception {
+        EasyMock.expect(mMockDevice.executeShellCommand(SHELL_CMD_GET)).andReturn("\n0\n").once();
+        mOptionSetter.setOptionValue("expected-values", "3");
+        EasyMock.replay(mMockDevice);
+        try {
+            mSettingsPreparer.run(mMockDevice, mMockBuildInfo);
+            fail("TargetSetupError expected");
+        } catch (TargetSetupError e) {
+            //Expected
+        }
+    }
+
+    public void testIncorrectManyExpected() throws Exception {
+        EasyMock.expect(mMockDevice.executeShellCommand(SHELL_CMD_GET)).andReturn("\n0\n").once();
+        mOptionSetter.setOptionValue("expected-values", "2");
+        mOptionSetter.setOptionValue("expected-values", "3");
+        mOptionSetter.setOptionValue("expected-values", "6");
+        mOptionSetter.setOptionValue("expected-values", "7");
+        EasyMock.replay(mMockDevice);
+        try {
+            mSettingsPreparer.run(mMockDevice, mMockBuildInfo);
+            fail("TargetSetupError expected");
+        } catch (TargetSetupError e) {
+            //Expected
+        }
+    }
+
+    public void testCommandRun() throws Exception {
+        EasyMock.expect(mMockDevice.executeShellCommand(SHELL_CMD_PUT_7)).andReturn("\n");
+        mOptionSetter.setOptionValue("set-value", "7");
+        EasyMock.replay(mMockDevice);
+        mSettingsPreparer.run(mMockDevice, mMockBuildInfo);
+    }
+
+    public void testCommandRunWrongSetValue() throws Exception {
+        EasyMock.expect(mMockDevice.executeShellCommand(SHELL_CMD_PUT_8)).andReturn("\n");
+        mOptionSetter.setOptionValue("set-value", "8");
+        mOptionSetter.setOptionValue("expected-values", "7");
+        EasyMock.replay(mMockDevice);
+        try {
+            mSettingsPreparer.run(mMockDevice, mMockBuildInfo);
+            fail("TargetSetupError expected");
+        } catch (TargetSetupError e) {
+            //Expected
+        }
+    }
+
+    public void testIncorrectOneExpectedCommandRun() throws Exception {
+        EasyMock.expect(mMockDevice.executeShellCommand(SHELL_CMD_GET)).andReturn("\n0\n").once();
+        EasyMock.expect(mMockDevice.executeShellCommand(SHELL_CMD_PUT_7)).andReturn("\n");
+        mOptionSetter.setOptionValue("set-value", "7");
+        mOptionSetter.setOptionValue("expected-values", "7");
+    }
+
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestTest.java
new file mode 100644
index 0000000..ccab426
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.testtype;
+
+import junit.framework.TestCase;
+
+public class CompatibilityTestTest extends TestCase {
+
+    @Override
+    public void setUp() throws Exception {
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+    }
+
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
new file mode 100644
index 0000000..8714c1d
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.compatibility.common.tradefed.util.NoOpTestInvocationListener;
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.ITestFilterReceiver;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ModuleDefTest extends TestCase {
+
+    private static final String NAME = "ModuleName";
+    private static final String ABI = "mips64";
+    private static final String ID = AbiUtils.createId(ABI, NAME);
+    private static final String CLASS = "android.test.FoorBar";
+    private static final String METHOD_1 = "testBlah1";
+    private static final String TEST_1 = String.format("%s#%s", CLASS, METHOD_1);
+
+    public void testAccessors() throws Exception {
+        IAbi abi = new Abi(ABI, "");
+        MockRemoteTest mockTest = new MockRemoteTest();
+        IModuleDef def = new ModuleDef(NAME, abi, mockTest, new ArrayList<ITargetPreparer>());
+        assertEquals("Incorrect ID", ID, def.getId());
+        assertEquals("Incorrect ABI", ABI, def.getAbi().getName());
+        assertEquals("Incorrect Name", NAME, def.getName());
+    }
+
+    public void testAddFilters() throws Exception {
+        IAbi abi = new Abi(ABI, "");
+        MockRemoteTest mockTest = new MockRemoteTest();
+        ModuleDef def = new ModuleDef(NAME, abi, mockTest, new ArrayList<ITargetPreparer>());
+        def.addIncludeFilter(CLASS);
+        def.addExcludeFilter(TEST_1);
+        MockListener mockListener = new MockListener();
+        def.run(mockListener);
+        assertEquals("Expected one include filter", 1, mockTest.mIncludeFilters.size());
+        assertEquals("Expected one exclude filter", 1, mockTest.mExcludeFilters.size());
+        assertEquals("Incorrect include filter", CLASS, mockTest.mIncludeFilters.get(0));
+        assertEquals("Incorrect exclude filter", TEST_1, mockTest.mExcludeFilters.get(0));
+    }
+
+    private class MockRemoteTest implements IRemoteTest, ITestFilterReceiver {
+
+        private final List<String> mIncludeFilters = new ArrayList<>();
+        private final List<String> mExcludeFilters = new ArrayList<>();
+
+        @Override
+        public void addIncludeFilter(String filter) {
+            mIncludeFilters.add(filter);
+        }
+
+        @Override
+        public void addAllIncludeFilters(List<String> filters) {
+            mIncludeFilters.addAll(filters);
+        }
+
+        @Override
+        public void addExcludeFilter(String filter) {
+            mExcludeFilters.add(filter);
+        }
+
+        @Override
+        public void addAllExcludeFilters(List<String> filters) {
+            mExcludeFilters.addAll(filters);
+        }
+
+        @Override
+        public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+            // Do nothing
+        }
+
+    }
+
+    private class MockListener extends NoOpTestInvocationListener {}
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
new file mode 100644
index 0000000..4944f3a
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
+import com.android.compatibility.common.tradefed.testtype.ModuleRepo.ConfigFilter;
+import com.android.compatibility.common.tradefed.testtype.IModuleDef;
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.util.FileUtil;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ModuleRepoTest extends TestCase {
+
+    private static final String TOKEN =
+            "<target_preparer class=\"com.android.compatibility.common.tradefed.targetprep.TokenRequirement\">\n"
+            + "<option name=\"token\" value=\"%s\" />\n"
+            + "</target_preparer>\n";
+    private static final String CONFIG =
+            "<configuration description=\"Auto Generated File\">\n" +
+            "%s" +
+            "<test class=\"com.android.compatibility.common.tradefed.testtype.%s\">\n" +
+            "<option name=\"module\" value=\"%s\" />" +
+            "</test>\n" +
+            "</configuration>";
+    private static final String FOOBAR_TOKEN = "foobar";
+    private static final String SERIAL1 = "abc";
+    private static final String SERIAL2 = "def";
+    private static final String SERIAL3 = "ghi";
+    private static final Set<String> SERIALS = new HashSet<>();
+    private static final Set<IAbi> ABIS = new HashSet<>();
+    private static final List<String> DEVICE_TOKENS = new ArrayList<>();
+    private static final List<String> TEST_ARGS= new ArrayList<>();
+    private static final List<String> MODULE_ARGS = new ArrayList<>();
+    private static final List<String> INCLUDES = new ArrayList<>();
+    private static final List<String> EXCLUDES = new ArrayList<>();
+    private static final Set<String> FILES = new HashSet<>();
+    private static final String FILENAME = "%s.config";
+    private static final String ABI_32 = "armeabi-v7a";
+    private static final String ABI_64 = "arm64-v8a";
+    private static final String MODULE_NAME_A = "FooModuleA";
+    private static final String MODULE_NAME_B = "FooModuleB";
+    private static final String MODULE_NAME_C = "FooModuleC";
+    private static final String ID_A_32 = AbiUtils.createId(ABI_32, MODULE_NAME_A);
+    private static final String ID_A_64 = AbiUtils.createId(ABI_64, MODULE_NAME_A);
+    private static final String ID_B_32 = AbiUtils.createId(ABI_32, MODULE_NAME_B);
+    private static final String ID_B_64 = AbiUtils.createId(ABI_64, MODULE_NAME_B);
+    private static final String ID_C_32 = AbiUtils.createId(ABI_32, MODULE_NAME_C);
+    private static final String ID_C_64 = AbiUtils.createId(ABI_64, MODULE_NAME_C);
+    private static final String TEST_ARG = TestStub.class.getName() + ":foo:bar";
+    private static final String MODULE_ARG = "%s:blah:foobar";
+    private static final String TEST_STUB = "TestStub"; // Trivial test stub
+    private static final String SHARDABLE_TEST_STUB = "ShardableTestStub"; // Shardable and IBuildReceiver
+    static {
+        SERIALS.add(SERIAL1);
+        SERIALS.add(SERIAL2);
+        SERIALS.add(SERIAL3);
+        ABIS.add(new Abi(ABI_32, "32"));
+        ABIS.add(new Abi(ABI_64, "64"));
+        DEVICE_TOKENS.add(String.format("%s:%s", SERIAL3, FOOBAR_TOKEN));
+        TEST_ARGS.add(TEST_ARG);
+        MODULE_ARGS.add(String.format(MODULE_ARG, MODULE_NAME_A));
+        MODULE_ARGS.add(String.format(MODULE_ARG, MODULE_NAME_B));
+        MODULE_ARGS.add(String.format(MODULE_ARG, MODULE_NAME_C));
+        FILES.add(String.format(FILENAME, MODULE_NAME_A));
+        FILES.add(String.format(FILENAME, MODULE_NAME_B));
+        FILES.add(String.format(FILENAME, MODULE_NAME_C));
+    }
+    private IModuleRepo mRepo;
+    private File mTestsDir;
+    private IBuildInfo mBuild;
+
+    @Override
+    public void setUp() throws Exception {
+        mTestsDir = setUpConfigs();
+        ModuleRepo.sInstance = null;// Clear the instance so it gets recreated.
+        mRepo = ModuleRepo.getInstance();
+        mBuild = new CompatibilityBuildProvider().getBuild();
+    }
+
+    private File setUpConfigs() throws IOException {
+        File testsDir = FileUtil.createNamedTempDir("testcases");
+        createConfig(testsDir, MODULE_NAME_A, null);
+        createConfig(testsDir, MODULE_NAME_B, null);
+        createConfig(testsDir, MODULE_NAME_C, FOOBAR_TOKEN);
+        return testsDir;
+    }
+
+    private void createConfig(File testsDir, String name, String token) throws IOException {
+        createConfig(testsDir, name, token, TEST_STUB);
+    }
+
+    private void createConfig(File testsDir, String name, String token, String moduleClass) throws IOException {
+        File config = new File(testsDir, String.format(FILENAME, name));
+        String preparer = "";
+        if (token != null) {
+            preparer = String.format(TOKEN, token);
+        }
+        FileUtil.writeToFile(String.format(CONFIG, preparer, moduleClass, name), config);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        tearDownConfigs(mTestsDir);
+    }
+
+    private void tearDownConfigs(File testsDir) {
+        FileUtil.recursiveDelete(testsDir);
+    }
+
+    public void testInitialization() throws Exception {
+        mRepo.initialize(3, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
+                EXCLUDES, mBuild);
+        assertTrue("Should be initialized", mRepo.isInitialized());
+        assertEquals("Wrong number of shards", 3, mRepo.getNumberOfShards());
+        assertEquals("Wrong number of modules per shard", 2, mRepo.getModulesPerShard());
+        Map<String, Set<String>> deviceTokens = mRepo.getDeviceTokens();
+        assertEquals("Wrong number of devices with tokens", 1, deviceTokens.size());
+        Set<String> tokens = deviceTokens.get(SERIAL3);
+        assertEquals("Wrong number of tokens", 1, tokens.size());
+        assertTrue("Unexpected device token", tokens.contains(FOOBAR_TOKEN));
+        assertEquals("Wrong number of modules", 0, mRepo.getLargeModules().size());
+        assertEquals("Wrong number of modules", 0, mRepo.getMediumModules().size());
+        assertEquals("Wrong number of modules", 4, mRepo.getSmallModules().size());
+        List<IModuleDef> tokenModules = mRepo.getTokenModules();
+        assertEquals("Wrong number of modules with tokens", 2, tokenModules.size());
+        List<IModuleDef> serial1Modules = mRepo.getModules(SERIAL1);
+        assertEquals("Wrong number of modules", 2, serial1Modules.size());
+        List<IModuleDef> serial2Modules = mRepo.getModules(SERIAL2);
+        assertEquals("Wrong number of modules", 2, serial2Modules.size());
+        List<IModuleDef> serial3Modules = mRepo.getModules(SERIAL3);
+        assertEquals("Wrong number of modules", 2, serial3Modules.size());
+        // Serial 3 should have the modules with tokens
+        for (IModuleDef module : serial3Modules) {
+            assertEquals("Wrong module", MODULE_NAME_C, module.getName());
+        }
+        Set<String> serials = mRepo.getSerials();
+        assertEquals("Wrong number of serials", 3, serials.size());
+        assertTrue("Unexpected device serial", serials.containsAll(SERIALS));
+    }
+
+    public void testConfigFilter() throws Exception {
+        File[] configFiles = mTestsDir.listFiles(new ConfigFilter());
+        assertEquals("Wrong number of config files found.", 3, configFiles.length);
+        for (File file : configFiles) {
+            assertTrue(String.format("Unrecognised file: %s", file.getAbsolutePath()),
+                    FILES.contains(file.getName()));
+        }
+    }
+
+    public void testFiltering() throws Exception {
+        List<String> includeFilters = new ArrayList<>();
+        includeFilters.add(MODULE_NAME_A);
+        List<String> excludeFilters = new ArrayList<>();
+        excludeFilters.add(ID_A_32);
+        excludeFilters.add(MODULE_NAME_B);
+        mRepo.initialize(1, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, includeFilters,
+                excludeFilters, mBuild);
+        List<IModuleDef> modules = mRepo.getModules(SERIAL1);
+        assertEquals("Incorrect number of modules", 1, modules.size());
+        IModuleDef module = modules.get(0);
+        assertEquals("Incorrect ID", ID_A_64, module.getId());
+        checkArgs(module);
+    }
+
+    public void testParsing() throws Exception {
+        mRepo.initialize(1, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
+                EXCLUDES, mBuild);
+        List<IModuleDef> modules = mRepo.getModules(SERIAL3);
+        Set<String> idSet = new HashSet<>();
+        for (IModuleDef module : modules) {
+            idSet.add(module.getId());
+        }
+        assertEquals("Incorrect number of IDs", 6, idSet.size());
+        assertTrue("Missing ID_A_32", idSet.contains(ID_A_32));
+        assertTrue("Missing ID_A_64", idSet.contains(ID_A_64));
+        assertTrue("Missing ID_B_32", idSet.contains(ID_B_32));
+        assertTrue("Missing ID_B_64", idSet.contains(ID_B_64));
+        assertTrue("Missing ID_C_32", idSet.contains(ID_C_32));
+        assertTrue("Missing ID_C_64", idSet.contains(ID_C_64));
+        for (IModuleDef module : modules) {
+            checkArgs(module);
+        }
+    }
+
+    private void checkArgs(IModuleDef module) {
+        IRemoteTest test = module.getTest();
+        assertTrue("Incorrect test type", test instanceof TestStub);
+        TestStub stub = (TestStub) test;
+        assertEquals("Incorrect test arg", "bar", stub.mFoo);
+        assertEquals("Incorrect module arg", "foobar", stub.mBlah);
+    }
+
+    public void testSplit() throws Exception {
+        createConfig(mTestsDir, "sharder_1", null, SHARDABLE_TEST_STUB);
+        createConfig(mTestsDir, "sharder_2", null, SHARDABLE_TEST_STUB);
+        createConfig(mTestsDir, "sharder_3", null, SHARDABLE_TEST_STUB);
+        Set<IAbi> abis = new HashSet<>();
+        abis.add(new Abi(ABI_64, "64"));
+        ArrayList<String> emptyList = new ArrayList<>();
+
+        mRepo.initialize(3, mTestsDir, abis, DEVICE_TOKENS, emptyList, emptyList, emptyList,
+                         emptyList, mBuild);
+
+        List<IModuleDef> modules = new ArrayList<>();
+        modules.addAll(mRepo.getLargeModules());
+        modules.addAll(mRepo.getMediumModules());
+        modules.addAll(mRepo.getSmallModules());
+        modules.addAll(mRepo.getTokenModules());
+
+        int shardableCount = 0;
+        for (IModuleDef def : modules) {
+            IRemoteTest test = def.getTest();
+            if (test instanceof IShardableTest) {
+                assertNotNull("Build not set", ((ShardableTestStub)test).mBuildInfo);
+                shardableCount++;
+            }
+        }
+        assertEquals("Shards wrong", 3*3, shardableCount);
+    }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
new file mode 100644
index 0000000..52a1aad
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IShardableTest;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class ShardableTestStub implements IRemoteTest, IShardableTest, IBuildReceiver {
+
+    @Option(name = "module")
+    String mModule;
+    @Option(name = "foo")
+    String mFoo;
+    @Option(name = "blah")
+    String mBlah;
+
+    public IBuildInfo mBuildInfo = null;
+
+    Collection<IRemoteTest> mShards;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mBuildInfo = buildInfo;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    @Override
+    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+        // Do nothing
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Collection<IRemoteTest> split() {
+        Assert.assertNotNull(mBuildInfo);
+
+        mShards = new ArrayList<>();
+        for (int i = 0; i < 3; i++) {
+            mShards.add(new ShardableTestStub());
+        }
+        return mShards;
+    }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
new file mode 100644
index 0000000..8a6ab69
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.IRemoteTest;
+
+public class TestStub implements IRemoteTest {
+
+    @Option(name = "module")
+    String mModule;
+    @Option(name = "foo")
+    String mFoo;
+    @Option(name = "blah")
+    String mBlah;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+        // Do nothing
+    }
+
+}
diff --git a/common/host-side/util/Android.mk b/common/host-side/util/Android.mk
new file mode 100644
index 0000000..8747cf8
--- /dev/null
+++ b/common/host-side/util/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-hostsidelib
+
+LOCAL_JAVA_LIBRARIES := json-prebuilt
+
+LOCAL_MODULE := compatibility-host-util
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/DynamicConfigHandler.java b/common/host-side/util/src/com/android/compatibility/common/util/DynamicConfigHandler.java
new file mode 100644
index 0000000..b42faca
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/DynamicConfigHandler.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DynamicConfigHandler {
+
+    private static final String LOG_TAG = DynamicConfigHandler.class.getSimpleName();
+
+    // xml constant
+    private static final String NS = null; //representing null namespace
+    private static final String ENCODING = "UTF-8";
+
+    public static File getMergedDynamicConfigFile(File localConfigFile, String apfeConfigJson,
+            String moduleName) throws IOException, XmlPullParserException, JSONException {
+
+        DynamicConfig.Params localConfig = DynamicConfig.genParamsFromFile(localConfigFile);
+        DynamicConfig.Params apfeOverride = parseJsonToParam(apfeConfigJson);
+
+        localConfig.mDynamicParams.putAll(apfeOverride.mDynamicParams);
+        localConfig.mDynamicArrayParams.putAll(apfeOverride.mDynamicArrayParams);
+
+        File mergedConfigFile = storeMergedConfigFile(localConfig, moduleName);
+        return mergedConfigFile;
+    }
+
+    private static DynamicConfig.Params parseJsonToParam(String apfeConfigJson)
+            throws JSONException {
+        if (apfeConfigJson == null) return new DynamicConfig.Params();
+
+        Map<String, String> configMap = new HashMap<>();
+        Map<String, List<String>> configListMap = new HashMap<>();
+
+        JSONObject rootObj  = new JSONObject(new JSONTokener(apfeConfigJson));
+        if (rootObj.has("config")) {
+            JSONArray configArr = rootObj.getJSONArray("config");
+            for (int i = 0; i < configArr.length(); i++) {
+                JSONObject config = configArr.getJSONObject(i);
+                configMap.put(config.getString("key"), config.getString("value"));
+            }
+        }
+        if (rootObj.has("configList")) {
+            JSONArray configListArr = rootObj.getJSONArray("configList");
+            for (int i = 0; i < configListArr.length(); i++) {
+                JSONObject configList = configListArr.getJSONObject(i);
+                String key = configList.getString("key");
+                List<String> values = new ArrayList<>();
+                JSONArray configListValuesArr = configList.getJSONArray("value");
+                for (int j = 0; j < configListValuesArr.length(); j++) {
+                    values.add(configListValuesArr.getString(j));
+                }
+                configListMap.put(key, values);
+            }
+        }
+
+        DynamicConfig.Params param = new DynamicConfig.Params();
+        param.mDynamicParams = configMap;
+        param.mDynamicArrayParams = configListMap;
+        return param;
+    }
+
+    private static File storeMergedConfigFile(DynamicConfig.Params p, String moduleName)
+            throws XmlPullParserException, IOException {
+        XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer();
+
+        File parentFolder = new File(DynamicConfig.CONFIG_FOLDER_ON_HOST);
+        if (!parentFolder.exists()) parentFolder.mkdir();
+        File folder = new File(DynamicConfig.MERGED_CONFIG_FILE_FOLDER);
+        if (!folder.exists()) folder.mkdir();
+        File mergedConfigFile = new File(folder, moduleName+".dynamic");
+        OutputStream stream = new FileOutputStream(mergedConfigFile);
+        serializer.setOutput(stream, ENCODING);
+        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        serializer.startDocument(ENCODING, false);
+
+        serializer.startTag(NS, DynamicConfig.DYNAMIC_CONFIG_TAG);
+        for (String key : p.mDynamicParams.keySet()) {
+            serializer.startTag(NS, DynamicConfig.CONFIG_TAG);
+            serializer.attribute(NS, DynamicConfig.KEY_ATTR, key);
+            serializer.text(p.mDynamicParams.get(key));
+            serializer.endTag(NS, DynamicConfig.CONFIG_TAG);
+        }
+        for (String key : p.mDynamicArrayParams.keySet()) {
+            serializer.startTag(NS, DynamicConfig.CONFIG_LIST_TAG);
+            serializer.attribute(NS, DynamicConfig.KEY_ATTR, key);
+            for (String item: p.mDynamicArrayParams.get(key)) {
+                serializer.startTag(NS, DynamicConfig.ITEM_TAG);
+                serializer.text(item);
+                serializer.endTag(NS, DynamicConfig.ITEM_TAG);
+            }
+            serializer.endTag(NS, DynamicConfig.CONFIG_LIST_TAG);
+        }
+        serializer.endTag(NS, DynamicConfig.DYNAMIC_CONFIG_TAG);
+        serializer.endDocument();
+        return mergedConfigFile;
+    }
+}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/DynamicConfigHostSide.java b/common/host-side/util/src/com/android/compatibility/common/util/DynamicConfigHostSide.java
new file mode 100644
index 0000000..ac69034
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/DynamicConfigHostSide.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Load dynamic config for device side test cases
+ */
+public class DynamicConfigHostSide extends DynamicConfig {
+    private static String LOG_TAG = DynamicConfigHostSide.class.getSimpleName();
+
+    public DynamicConfigHostSide(String moduleName) throws IOException, XmlPullParserException {
+        File configFile = getConfigFile(new File(CONFIG_FOLDER_ON_HOST), moduleName);
+        initConfigFromXml(configFile);
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/MetricsReportLog.java b/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
similarity index 100%
rename from common/util/src/com/android/compatibility/common/util/MetricsReportLog.java
rename to common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/MetricsStore.java b/common/host-side/util/src/com/android/compatibility/common/util/MetricsStore.java
new file mode 100644
index 0000000..efe7182
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/MetricsStore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.compatibility.common.util;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A simple in-memory store for metrics results. This should be used for hostside metrics reporting.
+ */
+public class MetricsStore {
+
+    // needs concurrent version as there can be multiple client accessing this.
+    // But there is no additional protection for the same key as that should not happen.
+    private static final ConcurrentHashMap<String, ReportLog> mMap =
+            new ConcurrentHashMap<String, ReportLog>();
+
+    private MetricsStore() {}
+
+    /**
+     * Stores a result. Existing result with the same key will be replaced.
+     * Note that key is generated in the form of device_serial#class#method name.
+     * So there should be no concurrent test for the same (serial, class, method).
+     * @param deviceSerial
+     * @param abi
+     * @param classMethodName
+     * @param reportLog Contains the result to be stored
+     */
+    public static void storeResult(
+            String deviceSerial, String abi, String classMethodName, ReportLog reportLog) {
+        mMap.put(generateTestKey(deviceSerial, abi, classMethodName), reportLog);
+    }
+
+    /**
+     * retrieves a metric result for the given condition and remove it from the internal
+     * storage. If there is no result for the given condition, it will return null.
+     */
+    public static ReportLog removeResult(String deviceSerial, String abi, String classMethodName) {
+        return mMap.remove(generateTestKey(deviceSerial, abi, classMethodName));
+    }
+
+    /**
+     * @return test key in the form of device_serial#abi#class_name#method_name
+     */
+    private static String generateTestKey(String deviceSerial, String abi, String classMethodName) {
+        return String.format("%s#%s#%s", deviceSerial, abi, classMethodName);
+    }
+}
diff --git a/common/host-side/util/tests/Android.mk b/common/host-side/util/tests/Android.mk
new file mode 100644
index 0000000..a0e9a3b
--- /dev/null
+++ b/common/host-side/util/tests/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := compatibility-host-util junit json-prebuilt
+
+LOCAL_MODULE := compatibility-host-util-tests
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/common/host-side/util/tests/run_tests.sh b/common/host-side/util/tests/run_tests.sh
new file mode 100755
index 0000000..d4513f9
--- /dev/null
+++ b/common/host-side/util/tests/run_tests.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Copyright (C) 2015 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.
+
+# Helper script for running unit tests for compatibility libraries
+
+CTS_DIR=$(dirname ${0})/../../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+    compatibility-common-util-hostsidelib\
+    compatibility-common-util-tests\
+    compatibility-host-util\
+    compatibility-host-util-tests\
+    compatibility-mock-tradefed\
+    compatibility-tradefed-tests"
+
+run_tests "com.android.compatibility.common.util.HostUnitTests" "${JARS}" "${@}"
+
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
new file mode 100644
index 0000000..e2001fc
--- /dev/null
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.compatibility.common.util;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Unit tests for {@link DynamicConfigHandler}
+ */
+public class DynamicConfigHandlerTest extends TestCase {
+
+    private static final String localConfig =
+            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+            "<DynamicConfig>\n" +
+            "    <Config key=\"test-config-1\">test config 1</Config>\n" +
+            "    <Config key=\"test-config-2\">test config 2</Config>\n" +
+            "    <Config key=\"override-config-2\">test config 3</Config>\n" +
+            "    <ConfigList key=\"config-list\">\n" +
+            "        <Item>config0</Item>\n" +
+            "        <Item>config1</Item>\n" +
+            "        <Item>config2</Item>\n" +
+            "        <Item>config3</Item>\n" +
+            "        <Item>config4</Item>\n" +
+            "    </ConfigList>\n" +
+            "    <ConfigList key=\"override-config-list-2\">\n" +
+            "        <Item>A</Item>\n" +
+            "        <Item>B</Item>\n" +
+            "        <Item>C</Item>\n" +
+            "        <Item>D</Item>\n" +
+            "        <Item>E</Item>\n" +
+            "    </ConfigList>\n" +
+            "</DynamicConfig>\n";
+
+    private static final String overrideJson =
+            "{\n" +
+            "  \"config\": [\n" +
+            "    {\n" +
+            "      \"key\": \"version\",\n" +
+            "      \"value\": \"1.0\"\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"key\": \"suite\",\n" +
+            "      \"value\": \"CTS_V2\"\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"key\": \"override-config-1\",\n" +
+            "      \"value\": \"override-config-val-1\"\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"key\": \"override-config-2\",\n" +
+            "      \"value\": \"override-config-val-2\"\n" +
+            "    }\n" +
+            "  ],\n" +
+            "  \"configList\": [\n" +
+            "    {\n" +
+            "      \"key\": \"override-config-list-1\",\n" +
+            "      \"value\": [\n" +
+            "        \"override-config-list-val-1-1\",\n" +
+            "        \"override-config-list-val-1-2\"\n" +
+            "      ]\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"key\": \"override-config-list-2\",\n" +
+            "      \"value\": [\n" +
+            "        \"override-config-list-val-2-1\"\n" +
+            "      ]\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"key\": \"override-config-list-3\",\n" +
+            "      \"value\": []\n" +
+            "    }\n" +
+            "  ]\n" +
+            "}";
+
+    public void testDynamicConfigHandler() throws Exception {
+        String module = "test1";
+        File localConfigFile = createFileFromStr(localConfig, module);
+
+        File mergedFile = DynamicConfigHandler
+                .getMergedDynamicConfigFile(localConfigFile, overrideJson, module);
+
+        DynamicConfig.Params params = DynamicConfig.genParamsFromFile(mergedFile);
+
+        assertEquals("override-config-val-1", params.mDynamicParams.get("override-config-1"));
+        assertTrue(params.mDynamicArrayParams.get("override-config-list-1")
+                .contains("override-config-list-val-1-1"));
+        assertTrue(params.mDynamicArrayParams.get("override-config-list-1")
+                .contains("override-config-list-val-1-2"));
+        assertTrue(params.mDynamicArrayParams.get("override-config-list-3").size() == 0);
+
+        assertEquals("test config 1", params.mDynamicParams.get("test-config-1"));
+        assertTrue(params.mDynamicArrayParams.get("config-list").contains("config2"));
+
+        assertEquals("override-config-val-2", params.mDynamicParams.get("override-config-2"));
+        assertEquals(1, params.mDynamicArrayParams.get("override-config-list-2").size());
+        assertTrue(params.mDynamicArrayParams.get("override-config-list-2")
+                .contains("override-config-list-val-2-1"));
+    }
+
+
+    private File createFileFromStr(String configStr, String module) throws IOException {
+        File file = File.createTempFile(module, "dynamic");
+        FileOutputStream stream = null;
+        try {
+            stream = new FileOutputStream(file);
+            stream.write(configStr.getBytes());
+            stream.flush();
+        } finally {
+            if (stream != null) {
+                stream.close();
+            }
+        }
+        return file;
+    }
+}
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java
new file mode 100644
index 0000000..8cf1e3f
--- /dev/null
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * A test suite for all host util unit tests.
+ * <p/>
+ * All tests listed here should be self-contained, and do not require any external dependencies.
+ */
+public class HostUnitTests extends TestSuite {
+
+    public HostUnitTests() {
+        super();
+        addTestSuite(DynamicConfigHandlerTest.class);
+        addTestSuite(MetricsStoreTest.class);
+    }
+
+    public static Test suite() {
+        return new HostUnitTests();
+    }
+}
\ No newline at end of file
diff --git a/common/util/tests/src/com/android/compatibility/common/util/MetricsStoreTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/MetricsStoreTest.java
similarity index 100%
rename from common/util/tests/src/com/android/compatibility/common/util/MetricsStoreTest.java
rename to common/host-side/util/tests/src/com/android/compatibility/common/util/MetricsStoreTest.java
diff --git a/common/host-side/xml-plan-generator/Android.mk b/common/host-side/xml-plan-generator/Android.mk
deleted file mode 100644
index 53718e5..0000000
--- a/common/host-side/xml-plan-generator/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := compatibility-common-util-hostsidelib_v2
-
-LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib
-
-LOCAL_JAR_MANIFEST := MANIFEST.mf
-
-LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
-
-LOCAL_MODULE := compatibility-xml-plan-generator_v2
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-###############################################################################
-# Build the tests
-###############################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, tests/src)
-
-LOCAL_JAVA_LIBRARIES := compatibility-tradefed_v2 compatibility-xml-plan-generator_v2 junit
-
-LOCAL_MODULE := compatibility-xml-plan-generator-tests_v2
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/xml-plan-generator/MANIFEST.mf b/common/host-side/xml-plan-generator/MANIFEST.mf
deleted file mode 100644
index 95aee0d..0000000
--- a/common/host-side/xml-plan-generator/MANIFEST.mf
+++ /dev/null
@@ -1,3 +0,0 @@
-Manifest-Version: 1.0
-Main-Class: com.android.compatibility.common.xmlgenerator.XmlPlanGenerator
-Class-Path: compatibility-common-util-hostsidelib_v2.jar
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/Test.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/Test.java
deleted file mode 100644
index d3e1d88..0000000
--- a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/Test.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.compatibility.common.xmlgenerator;
-
-public class Test {
-
-    private final String mName;
-
-    public Test(String name) {
-        mName = name;
-    }
-
-    public String getName() {
-        return mName;
-    }
-}
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestCase.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestCase.java
deleted file mode 100644
index 65b4aa3..0000000
--- a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestCase.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.compatibility.common.xmlgenerator;
-
-import java.util.ArrayList;
-
-public class TestCase {
-
-    private final String mName;
-    private final ArrayList<Test> mTests = new ArrayList<Test>();
-
-    public TestCase(String name) {
-        mName = name;
-    }
-
-    public void addTest(Test test) {
-        mTests.add(test);
-    }
-
-    public String getName() {
-        return mName;
-    }
-
-    public ArrayList<Test> getTests() {
-        return mTests;
-    }
-}
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestListParser.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestListParser.java
deleted file mode 100644
index 6880440..0000000
--- a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestListParser.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.compatibility.common.xmlgenerator;
-
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Scanner;
-
-/**
- * Parser of test lists in the form;
- *
- * suite:android.sample
- * case:SampleTest
- * test:testA
- * test:testB
- * suite:android.sample.ui
- * case:SampleUiTest
- * test:testA
- * test:testB
- */
-public class TestListParser {
-
-    private TestListParser() {}
-
-    public static HashMap<String, TestSuite> parse(InputStream input) {
-        final HashMap<String, TestSuite> suites = new HashMap<String, TestSuite>();
-        TestSuite currentSuite = null;
-        TestCase currentCase = null;
-        Scanner in = null;
-        try {
-            in = new Scanner(input);
-            while (in.hasNextLine()) {
-                final String line = in.nextLine();
-                final String[] parts = line.split(":");
-                if (parts.length != 2) {
-                    throw new RuntimeException("Invalid Format: " + line);
-                }
-                final String key = parts[0];
-                final String value = parts[1];
-                if (currentSuite == null) {
-                    if (!"suite".equals(key)) {
-                        throw new RuntimeException("TestSuite Expected");
-                    }
-                    final String[] names = value.split("\\.");
-                    for (int i = 0; i < names.length; i++) {
-                        final String name = names[i];
-                        if (currentSuite != null) {
-                            if (currentSuite.hasTestSuite(name)) {
-                                currentSuite = currentSuite.getTestSuite(name);
-                            } else {
-                                final TestSuite newSuite = new TestSuite(name);
-                                currentSuite.addTestSuite(newSuite);
-                                currentSuite = newSuite;
-                            }
-                        } else if (suites.containsKey(name)) {
-                            currentSuite = suites.get(name);
-                        } else {
-                            currentSuite = new TestSuite(name);
-                            suites.put(name, currentSuite);
-                        }
-                    }
-                } else if (currentCase == null) {
-                    if (!"case".equals(key)) {
-                        throw new RuntimeException("TestCase Expected");
-                    }
-                    currentCase = new TestCase(value);
-                    currentSuite.addTestCase(currentCase);
-                } else {
-                    if (!"test".equals(key)) {
-                        throw new RuntimeException("Test Expected");
-                    }
-                    currentCase.addTest(new Test(value));
-                }
-            }
-        } finally {
-            if (in != null) {
-                in.close();
-            }
-        }
-        return suites;
-    }
-}
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestSuite.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestSuite.java
deleted file mode 100644
index db4fd07c..0000000
--- a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/TestSuite.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.compatibility.common.xmlgenerator;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-public class TestSuite {
-
-    private final String mName;
-    private final HashMap<String, TestSuite> mTestSuites = new HashMap<String, TestSuite>();
-    private final ArrayList<TestCase> mTestCases = new ArrayList<TestCase>();
-
-    public TestSuite(String name) {
-        mName = name;
-    }
-
-    public boolean hasTestSuite(String name) {
-        return mTestSuites.containsKey(name);
-    }
-
-    public TestSuite getTestSuite(String name) {
-        return mTestSuites.get(name);
-    }
-
-    public void addTestSuite(TestSuite testSuite) {
-        mTestSuites.put(testSuite.getName(), testSuite);
-    }
-
-    public void addTestCase(TestCase testCase) {
-        mTestCases.add(testCase);
-    }
-
-    public String getName() {
-        return mName;
-    }
-
-    public HashMap<String, TestSuite> getTestSuites() {
-        return mTestSuites;
-    }
-
-    public ArrayList<TestCase> getTestCases() {
-        return mTestCases;
-    }
-}
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java
deleted file mode 100644
index efb53d5..0000000
--- a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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.compatibility.common.xmlgenerator;
-
-import com.android.compatibility.common.util.KeyValueArgsParser;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-import vogar.ExpectationStore;
-import vogar.ModeId;
-import vogar.Result;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-
-/**
- * Passes the scanner output and outputs an xml description of the tests.
- */
-public class XmlPlanGenerator {
-
-    private final ExpectationStore mExpectations;
-    private final String mAppNameSpace;
-    private final String mAppPackageName;
-    private final String mName;
-    private final String mRunner;
-    private final String mTargetBinaryName;
-    private final String mTargetNameSpace;
-    private final String mJarPath;
-    private final String mTestType;
-    private final String mOutput;
-
-    private XmlPlanGenerator(ExpectationStore expectations, String appNameSpace,
-            String appPackageName, String name, String runner, String targetBinaryName,
-            String targetNameSpace, String jarPath, String testType, String output) {
-        mExpectations = expectations;
-        mAppNameSpace = appNameSpace;
-        mAppPackageName = appPackageName;
-        mName = name;
-        mRunner = runner;
-        mTargetBinaryName = targetBinaryName;
-        mTargetNameSpace = targetNameSpace;
-        mJarPath = jarPath;
-        mTestType = testType;
-        mOutput = output;
-    }
-
-    private void writePackageXml() throws IOException {
-        OutputStream out = System.out;
-        if (mOutput != null) {
-            out = new FileOutputStream(mOutput);
-        }
-        PrintWriter writer = null;
-        try {
-            writer = new PrintWriter(out);
-            writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
-            writeTestPackage(writer);
-        } finally {
-            if (writer != null) {
-                writer.close();
-            }
-        }
-    }
-
-    private void writeTestPackage(PrintWriter writer) {
-        writer.append("<TestPackage");
-        if (mAppNameSpace != null) {
-            writer.append(" appNameSpace=\"").append(mAppNameSpace).append("\"");
-        }
-
-        writer.append(" appPackageName=\"").append(mAppPackageName).append("\"");
-        writer.append(" name=\"").append(mName).append("\"");
-
-        if (mRunner != null) {
-            writer.append(" runner=\"").append(mRunner).append("\"");
-        }
-
-        if (mAppNameSpace != null && mTargetNameSpace != null
-                && !mAppNameSpace.equals(mTargetNameSpace)) {
-            writer.append(" targetBinaryName=\"").append(mTargetBinaryName).append("\"");
-            writer.append(" targetNameSpace=\"").append(mTargetNameSpace).append("\"");
-        }
-
-        if (mTestType != null && !mTestType.isEmpty()) {
-            writer.append(" testType=\"").append(mTestType).append("\"");
-        }
-
-        if (mJarPath != null) {
-            writer.append(" jarPath=\"").append(mJarPath).append("\"");
-        }
-
-        writer.println(" version=\"1.0\">");
-
-        final HashMap<String, TestSuite> suites = TestListParser.parse(System.in);
-        if (suites.isEmpty()) {
-            throw new RuntimeException("No TestSuites Found");
-        }
-        writeTestSuites(writer, suites, "");
-        writer.println("</TestPackage>");
-    }
-
-    private void writeTestSuites(PrintWriter writer, HashMap<String, TestSuite> suites, String name) {
-        for (String suiteName : suites.keySet()) {
-            final TestSuite suite = suites.get(suiteName);
-            writer.append("<TestSuite name=\"").append(suiteName).println("\">");
-            final String fullname = name + suiteName + ".";
-            writeTestSuites(writer, suite.getTestSuites(), fullname);
-            writeTestCases(writer, suite.getTestCases(), fullname);
-            writer.println("</TestSuite>");
-        }
-    }
-
-    private void writeTestCases(PrintWriter writer, ArrayList<TestCase> cases, String name) {
-        for (TestCase testCase : cases) {
-            final String caseName = testCase.getName();
-            writer.append("<TestCase name=\"").append(caseName).println("\">");
-            final String fullname = name + caseName;
-            writeTests(writer, testCase.getTests(), fullname);
-            writer.println("</TestCase>");
-        }
-    }
-
-    private void writeTests(PrintWriter writer, ArrayList<Test> tests, String name) {
-        if (tests.isEmpty()) {
-            throw new RuntimeException("No Tests Found");
-        }
-        for (Test test : tests) {
-            final String testName = test.getName();
-            writer.append("<Test name=\"").append(testName).append("\"");
-            final String fullname = name + "#" + testName;
-            if (isKnownFailure(mExpectations, fullname)) {
-                writer.append(" expectation=\"failure\"");
-            }
-            writer.println(" />");
-        }
-    }
-
-    public static boolean isKnownFailure(ExpectationStore store, String fullname) {
-        return store != null && store.get(fullname).getResult() != Result.SUCCESS;
-    }
-
-    public static void main(String[] args) throws Exception {
-        final HashMap<String, String> argsMap = KeyValueArgsParser.parse(args);
-        final String packageName = argsMap.get("-p");
-        final String name = argsMap.get("-n");
-        final String testType = argsMap.get("-t");
-        final String jarPath = argsMap.get("-j");
-        final String instrumentation = argsMap.get("-i");
-        final String manifest = argsMap.get("-m");
-        final String expectations = argsMap.get("-e");
-        final String output = argsMap.get("-o");
-        String appNameSpace = argsMap.get("-a");
-        String targetNameSpace = argsMap.get("-r");
-        if (packageName == null || name == null) {
-            usage(args);
-        }
-        String runner = null;
-        if (manifest != null) {
-            Document m = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(manifest);
-            Element elem = m.getDocumentElement();
-            appNameSpace = elem.getAttribute("package");
-            runner = getElementAttribute(elem, "instrumentation", "android:name");
-            targetNameSpace = getElementAttribute(elem, "instrumentation", "android:targetPackage");
-        }
-
-        final HashSet<File> expectationFiles = new HashSet<File>();
-        if (expectations != null) {
-            expectationFiles.add(new File(expectations));
-        }
-        final ExpectationStore store = ExpectationStore.parse(expectationFiles, ModeId.DEVICE);
-        XmlPlanGenerator generator = new XmlPlanGenerator(store, appNameSpace, packageName, name,
-            runner, instrumentation, targetNameSpace, jarPath, testType, output);
-        generator.writePackageXml();
-    }
-
-    private static String getElementAttribute(Element parent, String elem, String name) {
-        NodeList nodeList = parent.getElementsByTagName(elem);
-        if (nodeList.getLength() > 0) {
-             Element element = (Element) nodeList.item(0);
-             return element.getAttribute(name);
-        }
-        return null;
-    }
-
-    private static void usage(String[] args) {
-        System.err.println("Arguments: " + Arrays.toString(args));
-        System.err.println("Usage: compatibility-xml-plan-generator -p PACKAGE_NAME -n NAME" +
-            "[-t TEST_TYPE] [-j JAR_PATH] [-i INSTRUMENTATION] [-m MANIFEST] [-e EXPECTATIONS]" +
-            "[-o OUTPUT]");
-        System.exit(1);
-    }
-}
diff --git a/common/host-side/xml-plan-generator/tests/src/com/android/compatibility/common/xmlgenerator/XmlPlanGeneratorTest.java b/common/host-side/xml-plan-generator/tests/src/com/android/compatibility/common/xmlgenerator/XmlPlanGeneratorTest.java
deleted file mode 100644
index 082af17..0000000
--- a/common/host-side/xml-plan-generator/tests/src/com/android/compatibility/common/xmlgenerator/XmlPlanGeneratorTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.compatibility.common.xmlgenerator;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Scanner;
-
-public class XmlPlanGeneratorTest extends TestCase {
-
-    private static final String JAR = "out/host/linux-x86/framework/compatibility-xml-plan-generator_v2.jar";
-    private static final String PACKAGE_NAME = "com.android.test";
-    private static final String NAME = "ValidTest";
-    private static final String VALID_RESULT =
-        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
-        "<TestPackage appPackageName=\"com.android.test\" name=\"ValidTest\" version=\"1.0\">" +
-        "<TestSuite name=\"com\">" +
-        "<TestSuite name=\"android\">" +
-        "<TestSuite name=\"test\">" +
-        "<TestCase name=\"ValidTest\">" +
-        "<Test name=\"testA\" />" +
-        "</TestCase>" +
-        "</TestSuite>" +
-        "</TestSuite>" +
-        "</TestSuite>" +
-        "</TestPackage>";
-
-    private static final String VALID =
-        "suite:com.android.test\n" +
-        "case:ValidTest\n" +
-        "test:testA\n";
-
-    private static final String INVALID_A = "";
-
-    private static final String INVALID_B =
-        "suite:com.android.test\n" +
-        "case:InvalidTest\n";
-
-    private static final String INVALID_C =
-        "uh oh";
-
-    private static final String INVALID_D =
-        "test:testA\n" +
-        "case:InvalidTest\n" +
-        "suite:com.android.test\n";
-
-    private static final String INVALID_E =
-        "suite:com.android.test\n" +
-        "test:testA\n" +
-        "case:InvalidTest\n";
-
-    public void testValid() throws Exception {
-        assertEquals(VALID_RESULT, runGenerator(VALID));
-    }
-
-    public void testInvalidA() throws Exception {
-        assertNull(runGenerator(INVALID_A));
-    }
-
-    public void testInvalidB() throws Exception {
-        assertNull(runGenerator(INVALID_B));
-    }
-
-    public void testTestListParserInvalidFormat() throws Exception {
-        runTestListParser(INVALID_C);
-    }
-
-    public void testTestListParserSuiteExpected() throws Exception {
-        runTestListParser(INVALID_D);
-    }
-
-    public void testTestListParserCaseExpected() throws Exception {
-        runTestListParser(INVALID_E);
-    }
-
-    private static String runGenerator(String input) throws Exception {
-        ArrayList<String> args = new ArrayList<String>();
-        args.add("java");
-        args.add("-jar");
-        args.add(JAR);
-        args.add("-p");
-        args.add(PACKAGE_NAME);
-        args.add("-n");
-        args.add(NAME);
-
-        final Process p = new ProcessBuilder(args).start();
-        final PrintWriter out = new PrintWriter(p.getOutputStream());
-        out.print(input);
-        out.flush();
-        out.close();
-        final StringBuilder output = new StringBuilder();
-        final Scanner in = new Scanner(p.getInputStream());
-        while (in.hasNextLine()) {
-            output.append(in.nextLine());
-        }
-        int ret = p.waitFor();
-        if (ret == 0) {
-            return output.toString();
-        }
-        return null;
-    }
-
-    private static void runTestListParser(String input) throws Exception {
-        try {
-            final ByteArrayInputStream in = new ByteArrayInputStream(input.getBytes());
-            final HashMap<String, TestSuite> suites = TestListParser.parse(in);
-            fail();
-        } catch (RuntimeException e) {}
-    }
-}
diff --git a/common/util/Android.mk b/common/util/Android.mk
index 84ced65..d011636 100644
--- a/common/util/Android.mk
+++ b/common/util/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_MODULE := compatibility-common-util-devicesidelib_v2
+LOCAL_MODULE := compatibility-common-util-devicesidelib
 
 LOCAL_SDK_VERSION := current
 
@@ -40,27 +40,10 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_MODULE := compatibility-common-util-hostsidelib_v2
+LOCAL_MODULE := compatibility-common-util-hostsidelib
 
-LOCAL_STATIC_JAVA_LIBRARIES := kxml2-2.3.0
+LOCAL_STATIC_JAVA_LIBRARIES := junit kxml2-2.3.0
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
-###############################################################################
-# Build the tests
-###############################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, tests/src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-                        junit \
-                        kxml2-2.3.0 \
-                        compatibility-common-util-hostsidelib_v2
-
-LOCAL_MODULE := compatibility-common-util-tests_v2
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_JAVA_LIBRARY)
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/common/util/run_unit_tests.sh b/common/util/run_unit_tests.sh
deleted file mode 100755
index 04a6745..0000000
--- a/common/util/run_unit_tests.sh
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/bash
-
-# 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.
-
-# helper script for running the cts common unit tests
-
-checkFile() {
-    if [ ! -f "$1" ]; then
-        echo "Unable to locate $1"
-        exit
-    fi;
-}
-
-# check if in Android build env
-if [ ! -z ${ANDROID_BUILD_TOP} ]; then
-    HOST=`uname`
-    if [ "$HOST" == "Linux" ]; then
-        OS="linux-x86"
-    elif [ "$HOST" == "Darwin" ]; then
-        OS="darwin-x86"
-    else
-        echo "Unrecognized OS"
-        exit
-    fi;
-fi;
-
-JAR_DIR=${ANDROID_BUILD_TOP}/out/host/$OS/framework
-JARS="tradefed-prebuilt.jar compatibility-common-util-hostsidelib_v2.jar compatibility-common-util-tests_v2.jar"
-
-for JAR in $JARS; do
-    checkFile ${JAR_DIR}/${JAR}
-    JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}
-done
-
-java $RDBG_FLAG \
-  -cp ${JAR_PATH} com.android.tradefed.command.Console run singleCommand host -n --class com.android.compatibility.common.util.UnitTests "$@"
-
diff --git a/common/util/src/com/android/compatibility/common/util/AbiUtils.java b/common/util/src/com/android/compatibility/common/util/AbiUtils.java
new file mode 100644
index 0000000..ef42a00
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/AbiUtils.java
@@ -0,0 +1,200 @@
+/*
+ * 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.compatibility.common.util;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utility class for handling device ABIs
+ */
+public class AbiUtils {
+
+    /**
+     * The set of 32Bit ABIs.
+     */
+    private static final Set<String> ABIS_32BIT = new HashSet<String>();
+
+    /**
+     * The set of 64Bit ABIs.
+     */
+    private static final Set<String> ABIS_64BIT = new HashSet<String>();
+
+    /**
+     * The set of ARM ABIs.
+     */
+    private static final Set<String> ARM_ABIS = new HashSet<String>();
+
+    /**
+     * The set of Intel ABIs.
+     */
+    private static final Set<String> INTEL_ABIS = new HashSet<String>();
+
+    /**
+     * The set of Mips ABIs.
+     */
+    private static final Set<String> MIPS_ABIS = new HashSet<String>();
+
+    /**
+     * The set of ABI names which Compatibility supports.
+     */
+    private static final Set<String> ABIS_SUPPORTED_BY_COMPATIBILITY = new HashSet<String>();
+
+    /**
+     * The map of architecture to ABI.
+     */
+    private static final Map<String, Set<String>> ARCH_TO_ABIS = new HashMap<String, Set<String>>();
+    static {
+        ABIS_32BIT.add("armeabi-v7a");
+        ABIS_32BIT.add("x86");
+        ABIS_32BIT.add("mips");
+
+        ABIS_64BIT.add("arm64-v8a");
+        ABIS_64BIT.add("x86_64");
+        ABIS_64BIT.add("mips64");
+
+        ARM_ABIS.add("armeabi-v7a");
+        ARM_ABIS.add("arm64-v8a");
+
+        INTEL_ABIS.add("x86");
+        INTEL_ABIS.add("x86_64");
+
+        MIPS_ABIS.add("mips");
+        MIPS_ABIS.add("mips64");
+
+        ARCH_TO_ABIS.put("arm", ARM_ABIS);
+        ARCH_TO_ABIS.put("arm64", ARM_ABIS);
+        ARCH_TO_ABIS.put("x86", INTEL_ABIS);
+        ARCH_TO_ABIS.put("x86_64", INTEL_ABIS);
+        ARCH_TO_ABIS.put("mips", MIPS_ABIS);
+        ARCH_TO_ABIS.put("mips64", MIPS_ABIS);
+
+        ABIS_SUPPORTED_BY_COMPATIBILITY.addAll(ARM_ABIS);
+        ABIS_SUPPORTED_BY_COMPATIBILITY.addAll(INTEL_ABIS);
+        ABIS_SUPPORTED_BY_COMPATIBILITY.addAll(MIPS_ABIS);
+    }
+
+    /**
+     * Private constructor to avoid instantiation.
+     */
+    private AbiUtils() {}
+
+    /**
+     * Returns the set of ABIs associated with the given architecture.
+     * @param arch The architecture to look up.
+     * @return a new Set containing the ABIs.
+     */
+    public static Set<String> getAbisForArch(String arch) {
+        if (arch == null || arch.isEmpty() || !ARCH_TO_ABIS.containsKey(arch)) {
+            return getAbisSupportedByCompatibility();
+        }
+        return new HashSet<String>(ARCH_TO_ABIS.get(arch));
+    }
+
+    /**
+     * Returns the set of ABIs supported by Compatibility.
+     * @return a new Set containing the supported ABIs.
+     */
+    public static Set<String> getAbisSupportedByCompatibility() {
+        return new HashSet<String>(ABIS_SUPPORTED_BY_COMPATIBILITY);
+    }
+
+    /**
+     * @param abi The ABI name to test.
+     * @return true if the given ABI is supported by Compatibility.
+     */
+    public static boolean isAbiSupportedByCompatibility(String abi) {
+        return ABIS_SUPPORTED_BY_COMPATIBILITY.contains(abi);
+    }
+
+    /**
+     * Creates a flag for the given ABI.
+     * @param abi the ABI to create the flag for.
+     * @return a string which can be add to a command sent to ADB.
+     */
+    public static String createAbiFlag(String abi) {
+        if (abi == null || abi.isEmpty() || !isAbiSupportedByCompatibility(abi)) {
+            return "";
+        }
+        return String.format("--abi %s ", abi);
+    }
+
+    /**
+     * Creates a unique id from the given ABI and name.
+     * @param abi The ABI to use.
+     * @param name The name to use.
+     * @return a string which uniquely identifies a run.
+     */
+    public static String createId(String abi, String name) {
+        return String.format("%s %s", abi, name);
+    }
+
+    /**
+     * Parses a unique id into the ABI and name.
+     * @param id The id to parse.
+     * @return a string array containing the ABI and name.
+     */
+    public static String[] parseId(String id) {
+        if (id == null || !id.contains(" ")) {
+            return new String[] {"", ""};
+        }
+        return id.split(" ");
+    }
+
+    /**
+     * @return the test name portion of the test id.
+     *         e.g. armeabi-v7a android.mytest = android.mytest
+     */
+    public static String parseTestName(String id) {
+        return parseId(id)[1];
+    }
+
+    /**
+     * @return the abi portion of the test id.
+     *         e.g. armeabi-v7a android.mytest = armeabi-v7a
+     */
+    public static String parseAbi(String id) {
+        return parseId(id)[0];
+    }
+
+    /**
+     * @param name The name of the ABI.
+     * @return The bitness of the ABI with the given name
+     */
+    public static String getBitness(String name) {
+        return ABIS_32BIT.contains(name) ? "32" : "64";
+    }
+
+    /**
+     * @param unsupportedAbiDescription A comma separated string containing abis.
+     * @return A List of Strings containing valid ABIs.
+     */
+    public static Set<String> parseAbiList(String unsupportedAbiDescription) {
+        Set<String> abiSet = new HashSet<>();
+        String[] descSegments = unsupportedAbiDescription.split(":");
+        if (descSegments.length == 2) {
+            for (String abi : descSegments[1].split(",")) {
+                String trimmedAbi = abi.trim();
+                if (isAbiSupportedByCompatibility(trimmedAbi)) {
+                    abiSet.add(trimmedAbi);
+                }
+            }
+        }
+        return abiSet;
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/CaseResult.java b/common/util/src/com/android/compatibility/common/util/CaseResult.java
new file mode 100644
index 0000000..e16ad1f
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/CaseResult.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Data structure for a Compatibility test case result.
+ */
+public class CaseResult implements ICaseResult {
+
+    private String mName;
+
+    private Map<String, ITestResult> mResults = new HashMap<>();
+
+    /**
+     * Creates a {@link CaseResult} for the given name, eg &lt;package-name&gt;.&lt;class-name&gt;
+     */
+    public CaseResult(String name) {
+        mName = name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ITestResult getOrCreateResult(String testName) {
+        ITestResult result = mResults.get(testName);
+        if (result == null) {
+            result = new TestResult(this, testName);
+            mResults.put(testName, result);
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ITestResult getResult(String testName) {
+        return mResults.get(testName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<ITestResult> getResults(TestStatus status) {
+        List<ITestResult> results = new ArrayList<>();
+        for (ITestResult result : mResults.values()) {
+            if (result.getResultStatus() == status) {
+                results.add(result);
+            }
+        }
+        return results;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<ITestResult> getResults() {
+        ArrayList<ITestResult> results = new ArrayList<>(mResults.values());
+        Collections.sort(results);
+        return results;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int countResults(TestStatus status) {
+        int total = 0;
+        for (ITestResult result : mResults.values()) {
+            if (result.getResultStatus() == status) {
+                total++;
+            }
+        }
+        return total;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int compareTo(ICaseResult another) {
+        return getName().compareTo(another.getName());
+    }
+
+}
\ No newline at end of file
diff --git a/common/util/src/com/android/compatibility/common/util/DynamicConfig.java b/common/util/src/com/android/compatibility/common/util/DynamicConfig.java
new file mode 100644
index 0000000..a0b1d5e
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/DynamicConfig.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Load dynamic config for test cases
+ */
+public class DynamicConfig {
+    public final static String MODULE_NAME = "module-name";
+
+    //XML constant
+    public static final String NS = null;
+    public static final String DYNAMIC_CONFIG_TAG = "DynamicConfig";
+    public static final String CONFIG_TAG = "Config";
+    public static final String CONFIG_LIST_TAG = "ConfigList";
+    public static final String ITEM_TAG = "Item";
+    public static final String KEY_ATTR = "key";
+
+    public final static String CONFIG_FOLDER_ON_DEVICE = "/sdcard/dynamic-config-files/";
+    public final static String CONFIG_FOLDER_ON_HOST =
+            System.getProperty("java.io.tmpdir") + "/dynamic-config-files/";
+    public final static String MERGED_CONFIG_FILE_FOLDER =
+            System.getProperty("java.io.tmpdir") + "/dynamic-config-files/merged";
+
+
+    protected Params params;
+
+    protected void initConfigFromXml(File file) throws XmlPullParserException, IOException {
+        params = genParamsFromFile(file);
+    }
+
+    public String getConfig(String key) {
+        return params.mDynamicParams.get(key);
+    }
+
+    public List<String> getConfigList(String key) {
+        return params.mDynamicArrayParams.get(key);
+    }
+
+    public static File getConfigFile(File configFolder, String moduleName)
+            throws FileNotFoundException {
+        File config =  new File(configFolder, String.format("%s.dynamic", moduleName));
+        if (!config.exists()) {
+            throw new FileNotFoundException(String.format("Cannot find %s.dynamic", moduleName));
+        }
+        return config;
+    }
+
+    public static class Params {
+        public Map<String, String> mDynamicParams = new HashMap<>();
+        public Map<String, List<String>> mDynamicArrayParams = new HashMap<>();
+    }
+
+    public static Params genParamsFromFile(File file) throws XmlPullParserException, IOException {
+        Params param = new Params();
+
+        XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
+        parser.setInput(new InputStreamReader(new FileInputStream(file)));
+
+        parser.nextTag();
+        parser.require(XmlPullParser.START_TAG, NS, DYNAMIC_CONFIG_TAG);
+
+        while (parser.nextTag() == XmlPullParser.START_TAG) {
+            if (parser.getName().equals(CONFIG_TAG)) {
+                String key = parser.getAttributeValue(NS, KEY_ATTR);
+                String value = parser.nextText();
+                parser.require(XmlPullParser.END_TAG, NS, CONFIG_TAG);
+                if (key != null && !key.isEmpty()) {
+                    param.mDynamicParams.put(key, value);
+                }
+            } else {
+                List<String> arrayValue = new ArrayList<>();
+                parser.require(XmlPullParser.START_TAG, NS, CONFIG_LIST_TAG);
+                String key = parser.getAttributeValue(NS, KEY_ATTR);
+                while (parser.nextTag() == XmlPullParser.START_TAG) {
+                    parser.require(XmlPullParser.START_TAG, NS, ITEM_TAG);
+                    arrayValue.add(parser.nextText());
+                    parser.require(XmlPullParser.END_TAG, NS, ITEM_TAG);
+                }
+                parser.require(XmlPullParser.END_TAG, NS, CONFIG_LIST_TAG);
+                if (key != null && !key.isEmpty()) {
+                    param.mDynamicArrayParams.put(key, arrayValue);
+                }
+            }
+        }
+        parser.require(XmlPullParser.END_TAG, NS, DYNAMIC_CONFIG_TAG);
+        return param;
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/ICaseResult.java b/common/util/src/com/android/compatibility/common/util/ICaseResult.java
new file mode 100644
index 0000000..99e646a
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/ICaseResult.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import java.util.List;
+
+/**
+ * Data structure for a Compatibility test case result.
+ */
+public interface ICaseResult extends Comparable<ICaseResult> {
+
+    String getName();
+
+    /**
+     * Gets a {@link ITestResult} for the given test, creating it if it doesn't exist.
+     *
+     * @param testName the name of the test eg &lt;method-name&gt;
+     * @return the {@link ITestResult} or <code>null</code>
+     */
+    ITestResult getOrCreateResult(String testName);
+
+    /**
+     * Gets the {@link ITestResult} for given test.
+     *
+     * @param testName the name of the test eg &lt;method-name&gt;
+     * @return the {@link ITestResult} or <code>null</code>
+     */
+    ITestResult getResult(String testName);
+
+    /**
+     * Gets all results sorted by name.
+     */
+    List<ITestResult> getResults();
+
+    /**
+     * Gets all results which have the given status.
+     */
+    List<ITestResult> getResults(TestStatus status);
+
+    /**
+     * Counts the number of results which have the given status.
+     */
+    int countResults(TestStatus status);
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/IInvocationResult.java b/common/util/src/com/android/compatibility/common/util/IInvocationResult.java
new file mode 100644
index 0000000..c1e5d28
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/IInvocationResult.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Interface for a the result of a single Compatibility invocation.
+ */
+public interface IInvocationResult {
+
+    /**
+     * @return the starting timestamp.
+     */
+    long getStartTime();
+
+    /**
+     * @param time the starting timestamp
+     */
+    void setStartTime(long time);
+
+    /**
+     * Count the number of results with given status.
+     */
+    int countResults(TestStatus result);
+
+    /**
+     * @param plan the plan associated with this result.
+     */
+    void setTestPlan(String plan);
+
+    /**
+     * @return the test plan associated with this result.
+     */
+    String getTestPlan();
+
+    /**
+     * Adds the given device serial to the result.
+     */
+    void addDeviceSerial(String serial);
+
+    /**
+     * @return the device serials associated with result.
+     */
+    Set<String> getDeviceSerials();
+
+    /**
+     * @return the {@link IModuleResult} for the given id, creating one if it doesn't exist
+     */
+    IModuleResult getOrCreateModule(String id);
+
+    /**
+     * @return the {@link IModuleResult}s sorted by id.
+     */
+    List<IModuleResult> getModules();
+
+    /**
+     * @return the directory containing this result.
+     */
+    File getResultDir();
+
+    /**
+     * Adds the given build info to the result.
+     */
+    void addBuildInfo(String key, String value);
+
+    /**
+     * Gets the {@link Map} of build info collected.
+     */
+    Map<String, String> getBuildInfo();
+}
diff --git a/common/util/src/com/android/compatibility/common/util/IModuleResult.java b/common/util/src/com/android/compatibility/common/util/IModuleResult.java
new file mode 100644
index 0000000..6d4efa1
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/IModuleResult.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import java.util.List;
+
+/**
+ * Data structure for a Compatibility test module result.
+ */
+public interface IModuleResult extends Comparable<IModuleResult> {
+
+    String getId();
+
+    String getName();
+
+    String getAbi();
+
+    void addRuntime(long elapsedTime);
+
+    long getRuntime();
+
+    /**
+     * Gets a {@link ICaseResult} for the given testcase, creating it if it doesn't exist.
+     *
+     * @param caseName the name of the testcase eg &lt;package-name&gt;&lt;class-name&gt;
+     * @return the {@link ICaseResult} or <code>null</code>
+     */
+    ICaseResult getOrCreateResult(String caseName);
+
+    /**
+     * Gets the {@link ICaseResult} result for given testcase.
+     *
+     * @param caseName the name of the testcase eg &lt;package-name&gt;&lt;class-name&gt;
+     * @return the {@link ITestResult} or <code>null</code>
+     */
+    ICaseResult getResult(String caseName);
+
+    /**
+     * Gets all results sorted by name.
+     */
+    List<ICaseResult> getResults();
+
+    /**
+     * Counts the number of results which have the given status.
+     */
+    int countResults(TestStatus status);
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/ITestResult.java b/common/util/src/com/android/compatibility/common/util/ITestResult.java
new file mode 100644
index 0000000..f27cf48
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/ITestResult.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+/**
+ * Represents a single test result.
+ */
+public interface ITestResult extends Comparable<ITestResult> {
+
+    /**
+     * @return The name of this test result.
+     */
+    String getName();
+
+    /**
+     * @return The full name of this test result, ie
+     * &lt;package-name&gt;.&lt;class-name&gt;#&lt;method-name&gt;
+     */
+    String getFullName();
+
+    /**
+     * @return The {@link TestStatus} of this result.
+     */
+    TestStatus getResultStatus();
+
+    /**
+     * Sets the {@link TestStatus} of the result and updates the end time of the test.
+     *
+     * @param status The {@link TestStatus} of this result.
+     */
+    void setResultStatus(TestStatus status);
+
+    /**
+     * @return The failure message to display
+     */
+    String getMessage();
+
+    /**
+     * @param message The message to display which describes the failure
+     */
+    void setMessage(String message);
+
+    /**
+     * @return The stack trace generated by the failure
+     */
+    String getStackTrace();
+
+    /**
+     * @param stackTrace the stack trace generated by the failure.
+     */
+    void setStackTrace(String stackTrace);
+
+    /**
+     * @return the metrics report.
+     */
+    ReportLog getReportLog();
+
+    /**
+     * @param report the metrics report.
+     */
+    void setReportLog(ReportLog report);
+
+    /**
+     * @return the path of the bug report generated of the failure.
+     */
+    String getBugReport();
+
+    /**
+     * @param path the path of the bug report generated of the failure.
+     */
+    void setBugReport(String path);
+
+    /**
+     * @return the path of the log file generated of the failure.
+     */
+    String getLog();
+
+    /**
+     * @param path the path of the log file generated of the failure.
+     */
+    void setLog(String path);
+
+    /**
+     * @return the path of the screenshot file generated of the failure.
+     */
+    String getScreenshot();
+
+    /**
+     * @param path the path of the screenshot file generated of the failure.
+     */
+    void setScreenshot(String path);
+
+    /**
+     * Report the test as a failure.
+     *
+     * @param trace the stacktrace of the failure.
+     */
+    void failed(String trace);
+
+    /**
+     * Report that the test has completed.
+     *
+     * @param report A report generated by the test, or null.
+     */
+    void passed(ReportLog report);
+
+    /**
+     * Resets the result.
+     */
+    void reset();
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/InvocationResult.java b/common/util/src/com/android/compatibility/common/util/InvocationResult.java
new file mode 100644
index 0000000..b499bc1
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/InvocationResult.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Data structure for the detailed Compatibility test results.
+ */
+public class InvocationResult implements IInvocationResult {
+
+    private long mTimestamp;
+    private Map<String, IModuleResult> mModuleResults = new LinkedHashMap<>();
+    private Map<String, String> mBuildInfo = new HashMap<>();
+    private Set<String> mSerials = new HashSet<>();
+    private String mTestPlan;
+    private File mResultDir;
+
+    /**
+     * @param resultDir
+     */
+    public InvocationResult(File resultDir) {
+        this(System.currentTimeMillis(), resultDir);
+    }
+
+    /**
+     * @param timestamp
+     * @param resultDir
+     */
+    public InvocationResult(long timestamp, File resultDir) {
+        setStartTime(timestamp);
+        mResultDir = resultDir;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<IModuleResult> getModules() {
+        ArrayList<IModuleResult> modules = new ArrayList<>(mModuleResults.values());
+        Collections.sort(modules);
+        return modules;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int countResults(TestStatus result) {
+        int total = 0;
+        for (IModuleResult m : mModuleResults.values()) {
+            total += m.countResults(result);
+        }
+        return total;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IModuleResult getOrCreateModule(String id) {
+        IModuleResult moduleResult = mModuleResults.get(id);
+        if (moduleResult == null) {
+            moduleResult = new ModuleResult(id);
+            mModuleResults.put(id, moduleResult);
+        }
+        return moduleResult;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addBuildInfo(String key, String value) {
+        mBuildInfo.put(key, value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Map<String, String> getBuildInfo() {
+        return mBuildInfo;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setStartTime(long time) {
+        mTimestamp = time;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long getStartTime() {
+        return mTimestamp;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setTestPlan(String plan) {
+        mTestPlan = plan;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getTestPlan() {
+        return mTestPlan;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addDeviceSerial(String serial) {
+        mSerials.add(serial);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Set<String> getDeviceSerials() {
+        return mSerials;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public File getResultDir() {
+        return mResultDir;
+    }
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/MeasureRun.java b/common/util/src/com/android/compatibility/common/util/MeasureRun.java
index d58b8d438..2b8905f 100644
--- a/common/util/src/com/android/compatibility/common/util/MeasureRun.java
+++ b/common/util/src/com/android/compatibility/common/util/MeasureRun.java
@@ -25,7 +25,7 @@
      */
     public void prepare(int i) throws Exception {
         // default empty implementation
-    };
+    }
 
     abstract public void run(int i) throws Exception;
 }
diff --git a/common/util/src/com/android/compatibility/common/util/MetricsStore.java b/common/util/src/com/android/compatibility/common/util/MetricsStore.java
deleted file mode 100644
index 9eeb94a..0000000
--- a/common/util/src/com/android/compatibility/common/util/MetricsStore.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.compatibility.common.util;
-
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * A simple in-memory store for metrics results. This should be used for hostside metrics reporting.
- */
-public class MetricsStore {
-
-    // needs concurrent version as there can be multiple client accessing this.
-    // But there is no additional protection for the same key as that should not happen.
-    private static final ConcurrentHashMap<String, ReportLog> mMap =
-            new ConcurrentHashMap<String, ReportLog>();
-
-    /**
-     * Stores a result. Existing result with the same key will be replaced.
-     * Note that key is generated in the form of device_serial#class#method name.
-     * So there should be no concurrent test for the same (serial, class, method).
-     * @param deviceSerial
-     * @param abi
-     * @param classMethodName
-     * @param reportLog Contains the result to be stored
-     */
-    public static void storeResult(
-            String deviceSerial, String abi, String classMethodName, ReportLog reportLog) {
-        mMap.put(generateTestKey(deviceSerial, abi, classMethodName), reportLog);
-    }
-
-    /**
-     * retrieves a metric result for the given condition and remove it from the internal
-     * storage. If there is no result for the given condition, it will return null.
-     */
-    public static ReportLog removeResult(String deviceSerial, String abi, String classMethodName) {
-        return mMap.remove(generateTestKey(deviceSerial, abi, classMethodName));
-    }
-
-    /**
-     * @return test key in the form of device_serial#abi#class_name#method_name
-     */
-    private static String generateTestKey(String deviceSerial, String abi, String classMethodName) {
-        return String.format("%s#%s#%s", deviceSerial, abi, classMethodName);
-    }
-}
diff --git a/common/util/src/com/android/compatibility/common/util/MetricsXmlSerializer.java b/common/util/src/com/android/compatibility/common/util/MetricsXmlSerializer.java
index 0e2b004..0f4b597 100644
--- a/common/util/src/com/android/compatibility/common/util/MetricsXmlSerializer.java
+++ b/common/util/src/com/android/compatibility/common/util/MetricsXmlSerializer.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.util.List;
 
+//TODO(stuartscott): Delete file for v2, ReportLog can serialize itself.
 /**
  * Serialize Metric data from {@link ReportLog} into compatibility report friendly XML
  */
@@ -36,26 +37,26 @@
         if (reportLog == null) {
             return;
         }
-        ReportLog.Result summary = reportLog.getSummary();
-        List<ReportLog.Result> detailedMetrics = reportLog.getDetailedMetrics();
+        ReportLog.Metric summary = reportLog.getSummary();
+        List<ReportLog.Metric> detailedMetrics = reportLog.getDetailedMetrics();
         // <Summary message="Average" scoreType="lower_better" unit="ms">195.2</Summary>
         if (summary != null) {
             mXmlSerializer.startTag(null, "Summary");
             mXmlSerializer.attribute(null, "message", summary.getMessage());
-            mXmlSerializer.attribute(null, "scoreType", summary.getType().getXmlString());
-            mXmlSerializer.attribute(null, "unit", summary.getUnit().getXmlString());
+            mXmlSerializer.attribute(null, "scoreType", summary.getType().toReportString());
+            mXmlSerializer.attribute(null, "unit", summary.getUnit().toReportString());
             mXmlSerializer.text(Double.toString(summary.getValues()[0]));
             mXmlSerializer.endTag(null, "Summary");
         }
 
         if (!detailedMetrics.isEmpty()) {
             mXmlSerializer.startTag(null, "Details");
-            for (ReportLog.Result result : detailedMetrics) {
+            for (ReportLog.Metric result : detailedMetrics) {
                 mXmlSerializer.startTag(null, "ValueArray");
-                mXmlSerializer.attribute(null, "source", result.getLocation());
+                mXmlSerializer.attribute(null, "source", result.getSource());
                 mXmlSerializer.attribute(null, "message", result.getMessage());
-                mXmlSerializer.attribute(null, "scoreType", result.getType().getXmlString());
-                mXmlSerializer.attribute(null, "unit", result.getUnit().getXmlString());
+                mXmlSerializer.attribute(null, "scoreType", result.getType().toReportString());
+                mXmlSerializer.attribute(null, "unit", result.getUnit().toReportString());
 
                 for (double value : result.getValues()) {
                     mXmlSerializer.startTag(null, "Value");
@@ -67,4 +68,4 @@
             mXmlSerializer.endTag(null, "Details");
         }
     }
-}
+}
\ No newline at end of file
diff --git a/common/util/src/com/android/compatibility/common/util/ModuleResult.java b/common/util/src/com/android/compatibility/common/util/ModuleResult.java
new file mode 100644
index 0000000..1f277f7
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/ModuleResult.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Data structure for a Compatibility test module result.
+ */
+public class ModuleResult implements IModuleResult {
+
+    private String mId;
+    private long mRuntime = 0;
+
+    private Map<String, ICaseResult> mResults = new HashMap<>();
+
+    /**
+     * Creates a {@link ModuleResult} for the given id, created with
+     * {@link AbiUtils#createId(String, String)}
+     */
+    public ModuleResult(String id) {
+        mId = id;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getId() {
+        return mId;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getName() {
+        return AbiUtils.parseTestName(mId);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getAbi() {
+        return AbiUtils.parseAbi(mId);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addRuntime(long elapsedTime) {
+        mRuntime += elapsedTime;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long getRuntime() {
+        return mRuntime;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ICaseResult getOrCreateResult(String caseName) {
+        ICaseResult result = mResults.get(caseName);
+        if (result == null) {
+            result = new CaseResult(caseName);
+            mResults.put(caseName, result);
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ICaseResult getResult(String caseName) {
+        return mResults.get(caseName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<ICaseResult> getResults() {
+        ArrayList<ICaseResult> results = new ArrayList<>(mResults.values());
+        Collections.sort(results);
+        return results;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int countResults(TestStatus status) {
+        int total = 0;
+        for (ICaseResult result : mResults.values()) {
+            total += result.countResults(status);
+        }
+        return total;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int compareTo(IModuleResult another) {
+        return getId().compareTo(another.getId());
+    }
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/MultipartForm.java b/common/util/src/com/android/compatibility/common/util/MultipartForm.java
new file mode 100644
index 0000000..4ae7860
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/MultipartForm.java
@@ -0,0 +1,167 @@
+/*
+ * 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.compatibility.common.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Builds a multipart form and submits it. */
+class MultipartForm {
+
+    private static final String FORM_DATA_BOUNDARY = "C75I55u3R3p0r73r";
+
+    /* package */ final String mServerUrl;
+    /* package */ final Map<String, String> mFormValues = new HashMap<String, String>();
+    /* package */ String mName;
+    /* package */ String mFileName;
+    /* package */ byte[] mData;
+
+    /**
+     * Creates a new multi-part form with the given serverUrl.
+     */
+    public MultipartForm(String serverUrl) {
+        mServerUrl = serverUrl;
+    }
+
+    /**
+     * Adds a key value attribute to the form.
+     *
+     * @param name the name of the attribute.
+     * @param value the attribute's value.
+     * @return the {@link MultipartForm} for easy chaining.
+     */
+    public MultipartForm addFormValue(String name, String value) {
+        mFormValues.put(name, value);
+        return this;
+    }
+
+    /**
+     * Adds the file as the payload of the form.
+     *
+     * @param name The name of attribute
+     * @param fileName The file's name
+     * @param data The file's data
+     * @return the {@link MultipartForm} for easy chaining.
+     */
+    public MultipartForm addFormFile(String name, String fileName, byte[] data) {
+        mName = name;
+        mFileName = fileName;
+        mData = data;
+        return this;
+    }
+
+    /**
+     * Submits the form to the server url.
+     *
+     * This will handle a redirection from the server.
+     *
+     * @throws IOException
+     */
+    public void submit() throws IOException {
+        String redirectUrl = submitForm(mServerUrl);
+        if (redirectUrl != null) {
+            submitForm(redirectUrl);
+        }
+    }
+
+    /**
+     * @param serverUrl to post the data to
+     * @return a url if the server redirected to another url
+     * @throws IOException
+     */
+    private String submitForm(String serverUrl) throws IOException {
+        HttpURLConnection connection = null;
+        try {
+            URL url = new URL(serverUrl);
+            connection = (HttpURLConnection) url.openConnection();
+            connection.setInstanceFollowRedirects(false);
+            connection.setRequestMethod("POST");
+            connection.setDoOutput(true);
+            connection.setRequestProperty("Content-Type",
+                    "multipart/form-data; boundary=" + FORM_DATA_BOUNDARY);
+
+            byte[] body = getContentBody();
+            connection.setRequestProperty("Content-Length", Integer.toString(body.length));
+
+            OutputStream output = connection.getOutputStream();
+            try {
+                output.write(body);
+            } finally {
+                output.close();
+            }
+
+            // Open the stream to get a response. Otherwise request will be cancelled.
+            InputStream input = connection.getInputStream();
+            input.close();
+
+            if (connection.getResponseCode() == 302) {
+                return connection.getHeaderField("Location");
+            }
+        } finally {
+            if (connection != null) {
+                connection.disconnect();
+            }
+        }
+
+        return null;
+    }
+
+    /* package */ byte[] getContentBody() throws IOException {
+        ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
+        PrintWriter writer = new PrintWriter(new OutputStreamWriter(byteOutput));
+        writer.println();
+
+        for (Map.Entry<String, String> formValue : mFormValues.entrySet()) {
+            writeFormField(writer, formValue.getKey(), formValue.getValue());
+        }
+
+        if (mData != null) {
+            writeFormFileHeader(writer, mName, mFileName);
+            writer.flush(); // Must flush here before writing to the byte stream!
+            byteOutput.write(mData);
+            writer.println();
+        }
+        writer.append("--").append(FORM_DATA_BOUNDARY).println("--");
+        writer.flush();
+        writer.close();
+        return byteOutput.toByteArray();
+    }
+
+    private void writeFormField(PrintWriter writer, String name, String value) {
+        writer.append("--").println(FORM_DATA_BOUNDARY);
+        writer.append("Content-Disposition: form-data; name=\"").append(name).println("\"");
+        writer.println();
+        writer.println(value);
+    }
+
+    private void writeFormFileHeader(PrintWriter writer, String name, String fileName) {
+        writer.append("--").println(FORM_DATA_BOUNDARY);
+        writer.append("Content-Disposition: form-data; name=\"").append(name);
+        writer.append("\"; filename=\"").append(fileName).println("\"");
+        writer.println("Content-Type: application/x-gzip");
+        writer.println("Content-Transfer-Encoding: binary");
+        writer.println();
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/ReportLog.java b/common/util/src/com/android/compatibility/common/util/ReportLog.java
index 7209ac8..445bbd4 100644
--- a/common/util/src/com/android/compatibility/common/util/ReportLog.java
+++ b/common/util/src/com/android/compatibility/common/util/ReportLog.java
@@ -16,66 +16,93 @@
 
 package com.android.compatibility.common.util;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
-import java.util.StringTokenizer;
-import java.util.regex.Pattern;
 
 /**
  * Utility class to add results to the report.
  */
 public class ReportLog implements Serializable {
 
-    private static final String LOG_SEPARATOR = "+++";
-    private static final String SUMMARY_SEPARATOR = "++++";
-    private static final String LOG_ELEM_SEPARATOR = "|";
-    private static final String EMPTY_CHAR = " ";
-    private Result mSummary;
-    private final List<Result> mDetails = new ArrayList<Result>();
+    private static final String ENCODING = "UTF-8";
+    private static final String TYPE = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer";
 
-    static class Result implements Serializable {
-        private String mLocation;
+    // XML constants
+    private static final String DETAIL_TAG = "Detail";
+    private static final String METRIC_TAG = "Metric";
+    private static final String MESSAGE_ATTR = "message";
+    private static final String SCORETYPE_ATTR = "score_type";
+    private static final String SCOREUNIT_ATTR = "score_unit";
+    private static final String SOURCE_ATTR = "source";
+    private static final String SUMMARY_TAG = "Summary";
+    private static final String VALUE_TAG = "Value";
+
+    private Metric mSummary;
+    private final List<Metric> mDetails = new ArrayList<>();
+
+    public static class Metric implements Serializable {
+        private static final int MAX_SOURCE_LENGTH = 200;
+        private static final int MAX_MESSAGE_LENGTH = 200;
+        private static final int MAX_NUM_VALUES = 1000;
+        private String mSource;
         private String mMessage;
         private double[] mValues;
         private ResultType mType;
         private ResultUnit mUnit;
-        private Double mTarget;
 
-
-        private Result(String location, String message, double[] values,
-                ResultType type, ResultUnit unit) {
-            this(location, message, values, null /*target*/, type, unit);
+        Metric(String source, String message, double value, ResultType type, ResultUnit unit) {
+            this(source, message, new double[] { value }, type, unit);
         }
 
         /**
-         * Creates a result object to be included in the report. Each object has a message
+         * Creates a metric array to be included in the report. Each object has a message
          * describing its values and enums to interpret them. In addition, each result also includes
          * class, method and line number information about the test which added this result which is
          * collected by looking at the stack trace.
          *
          * @param message A string describing the values
          * @param values An array of the values
-         * @param target Nullable. The target value.
          * @param type Represents how to interpret the values (eg. A lower score is better)
          * @param unit Represents the unit in which the values are (eg. Milliseconds)
          */
-        private Result(String location, String message, double[] values,
-                Double target, ResultType type, ResultUnit unit) {
-            mLocation = location;
-            mMessage = message;
-            mValues = values;
+        Metric(String source, String message, double[] values, ResultType type, ResultUnit unit) {
+            int sourceLength = source.length();
+            if (sourceLength > MAX_SOURCE_LENGTH) {
+                // Substring to the end
+                mSource = source.substring(sourceLength - MAX_SOURCE_LENGTH);
+            } else {
+                mSource = source;
+            }
+            int messageLength = message.length();
+            if (messageLength > MAX_MESSAGE_LENGTH) {
+                // Substring from the start
+                mMessage = message.substring(0, MAX_MESSAGE_LENGTH);
+            } else {
+                mMessage = message;
+            }
+            int valuesLength = values.length;
+            if (valuesLength > MAX_NUM_VALUES) {
+                // Subarray from the start
+                mValues = Arrays.copyOf(values, MAX_NUM_VALUES);
+            } else {
+                mValues = values;
+            }
             mType = type;
             mUnit = unit;
-            mTarget = target;
         }
 
-        public double getTarget() {
-            return mTarget;
-        }
-
-        public String getLocation() {
-            return mLocation;
+        public String getSource() {
+            return mSource;
         }
 
         public String getMessage() {
@@ -94,137 +121,212 @@
             return mUnit;
         }
 
-        /**
-         * Format:
-         * location|message|target|type|unit|value[s], target can be " " if there is no target set.
-         * log for array = classMethodName:line_number|message|unit|type|space separated values
-         */
-        String toEncodedString() {
-            StringBuilder builder = new StringBuilder()
-                    .append(mLocation)
-                    .append(LOG_ELEM_SEPARATOR)
-                    .append(mMessage)
-                    .append(LOG_ELEM_SEPARATOR)
-                    .append(mTarget != null ? mTarget : EMPTY_CHAR)
-                    .append(LOG_ELEM_SEPARATOR)
-                    .append(mType.name())
-                    .append(LOG_ELEM_SEPARATOR)
-                    .append(mUnit.name())
-                    .append(LOG_ELEM_SEPARATOR);
-            for (double value : mValues) {
-                builder.append(value).append(" ");
+        void serialize(XmlSerializer serializer)
+                throws IllegalArgumentException, IllegalStateException, IOException {
+            serializer.startTag(null, METRIC_TAG);
+            serializer.attribute(null, SOURCE_ATTR, getSource());
+            serializer.attribute(null, MESSAGE_ATTR, getMessage());
+            serializer.attribute(null, SCORETYPE_ATTR, getType().toReportString());
+            serializer.attribute(null, SCOREUNIT_ATTR, getUnit().toReportString());
+            for (double d : getValues()) {
+                serializer.startTag(null, VALUE_TAG);
+                serializer.text(Double.toString(d));
+                serializer.endTag(null, VALUE_TAG);
             }
-            return builder.toString();
+            serializer.endTag(null, METRIC_TAG);
         }
 
-        static Result fromEncodedString(String encodedString) {
-            String[] elems = encodedString.split(Pattern.quote(LOG_ELEM_SEPARATOR));
-            if (elems.length < 5) {
-                return null;
+        static Metric parse(XmlPullParser parser)
+                throws XmlPullParserException, IOException {
+            parser.require(XmlPullParser.START_TAG, null, METRIC_TAG);
+            String source = parser.getAttributeValue(null, SOURCE_ATTR);
+            String message = parser.getAttributeValue(null, MESSAGE_ATTR);
+            ResultType type = ResultType.parseReportString(
+                    parser.getAttributeValue(null, SCORETYPE_ATTR));
+            ResultUnit unit = ResultUnit.parseReportString(
+                    parser.getAttributeValue(null, SCOREUNIT_ATTR));
+            List<String> valuesList = new ArrayList<>();
+            while (parser.nextTag() == XmlPullParser.START_TAG) {
+                parser.require(XmlPullParser.START_TAG, null, VALUE_TAG);
+                valuesList.add(parser.nextText());
+                parser.require(XmlPullParser.END_TAG, null, VALUE_TAG);
             }
-
-            String[] valueStrArray = elems[5].split(" ");
-            double[] valueArray = new double[valueStrArray.length];
-            for (int i = 0; i < valueStrArray.length; i++) {
-                valueArray[i] = Double.parseDouble(valueStrArray[i]);
+            int length = valuesList.size();
+            double[] values = new double[length];
+            for (int i = 0; i < length; i++) {
+                values[i] = Double.parseDouble(valuesList.get(i));
             }
-            return new Result(
-                    elems[0], /*location*/
-                    elems[1], /*message*/
-                    valueArray, /*values*/
-                    elems[2].equals(EMPTY_CHAR) ? null : Double.parseDouble(elems[2]), /*target*/
-                    ResultType.valueOf(elems[3]), /*type*/
-                    ResultUnit.valueOf(elems[4])  /*unit*/);
+            parser.require(XmlPullParser.END_TAG, null, METRIC_TAG);
+            return new Metric(source, message, values, type, unit);
         }
     }
 
     /**
-     * Adds an array of values to the report.
+     * @param elem
+     */
+    /* package */ void addMetric(Metric elem) {
+        mDetails.add(elem);
+    }
+
+    /**
+     * Adds an array of metrics to the report.
+     *
+     * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
+     * NOTE: arrays with length over {@value Metric#MAX_NUM_VALUES} will be truncated.
      */
     public void addValues(String message, double[] values, ResultType type, ResultUnit unit) {
-        mDetails.add(new Result(Stacktrace.getTestCallerClassMethodNameLineNumber(),
+        addMetric(new Metric(Stacktrace.getTestCallerClassMethodNameLineNumber(),
                 message, values, type, unit));
     }
 
     /**
-     * Adds an array of values to the report.
+     * Adds an array of metrics to the report.
+     *
+     * NOTE: sources over {@value Metric#MAX_SOURCE_LENGTH} chars will be trimmed.
+     * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
+     * NOTE: arrays with length over {@value Metric#MAX_NUM_VALUES} will be truncated.
      */
-    public void addValues(
-            String message, double[] values, ResultType type, ResultUnit unit, String location) {
-        mDetails.add(new Result(location, message, values, type, unit));
+    public void addValues(String source, String message, double[] values, ResultType type,
+            ResultUnit unit) {
+        addMetric(new Metric(source, message, values, type, unit));
     }
 
     /**
-     * Adds a value to the report.
+     * Adds a metric to the report.
+     *
+     * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
      */
     public void addValue(String message, double value, ResultType type, ResultUnit unit) {
-        mDetails.add(new Result(Stacktrace.getTestCallerClassMethodNameLineNumber(), message,
-                new double[] {value}, type, unit));
+        addMetric(new Metric(Stacktrace.getTestCallerClassMethodNameLineNumber(), message,
+                value, type, unit));
     }
 
     /**
-     * Adds a value to the report.
+     * Adds a metric to the report.
+     *
+     * NOTE: sources over {@value Metric#MAX_SOURCE_LENGTH} chars will be trimmed.
+     * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
      */
-    public void addValue(String message, double value, ResultType type,
-            ResultUnit unit, String location) {
-        mDetails.add(new Result(location, message, new double[] {value}, type, unit));
+    public void addValue(String source, String message, double value, ResultType type,
+            ResultUnit unit) {
+        addMetric(new Metric(source, message, value, type, unit));
+    }
+
+    /**
+     * @param elem
+     */
+    /* package */ void setSummary(Metric elem) {
+        mSummary = elem;
     }
 
     /**
      * Sets the summary of the report.
+     *
+     * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
      */
     public void setSummary(String message, double value, ResultType type, ResultUnit unit) {
-        mSummary = new Result(Stacktrace.getTestCallerClassMethodNameLineNumber(),
-                message, new double[] {value}, type, unit);
+        setSummary(new Metric(Stacktrace.getTestCallerClassMethodNameLineNumber(),
+                message, value, type, unit));
     }
 
-    public Result getSummary() {
+    public Metric getSummary() {
         return mSummary;
     }
 
-    public List<Result> getDetailedMetrics() {
-        return new ArrayList<Result>(mDetails);
+    public List<Metric> getDetailedMetrics() {
+        return new ArrayList<Metric>(mDetails);
     }
 
     /**
-     * Parse a String encoded {@link com.android.compatibility.common.util.ReportLog}
+     * Serializes a given {@link ReportLog} to a String.
+     * @throws XmlPullParserException
+     * @throws IOException
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
      */
-    public static ReportLog fromEncodedString(String encodedString) {
-        ReportLog reportLog = new ReportLog();
-        StringTokenizer tok = new StringTokenizer(encodedString, SUMMARY_SEPARATOR);
-        if (tok.hasMoreTokens()) {
-            // Extract the summary
-            reportLog.mSummary = Result.fromEncodedString(tok.nextToken());
+    public static String serialize(ReportLog reportlog) throws XmlPullParserException,
+            IllegalArgumentException, IllegalStateException, IOException {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        XmlSerializer serializer = XmlPullParserFactory.newInstance(TYPE, null).newSerializer();
+        serializer.setOutput(byteArrayOutputStream, ENCODING);
+        serializer.startDocument(ENCODING, true);
+        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        serialize(serializer, reportlog);
+        serializer.endDocument();
+        return byteArrayOutputStream.toString(ENCODING);
+    }
+
+    /**
+     * Serializes a given {@link ReportLog} to XML.
+     * @param serializer
+     * @param reportLog
+     * @throws IOException
+     */
+    public static void serialize(XmlSerializer serializer, ReportLog reportLog)
+            throws IOException {
+        if (reportLog == null) {
+            throw new IllegalArgumentException("Metrics reports was null");
         }
-        if (tok.hasMoreTokens()) {
-            // Extract the detailed results
-            StringTokenizer detailedTok = new StringTokenizer(tok.nextToken(), LOG_SEPARATOR);
-            while (detailedTok.hasMoreTokens()) {
-                reportLog.mDetails.add(Result.fromEncodedString(detailedTok.nextToken()));
+        Metric summary = reportLog.getSummary();
+        List<Metric> detailedMetrics = reportLog.getDetailedMetrics();
+        if (summary == null) {
+            throw new IllegalArgumentException("Metrics reports must have a summary");
+        }
+        serializer.startTag(null, SUMMARY_TAG);
+        summary.serialize(serializer);
+        serializer.endTag(null, SUMMARY_TAG);
+
+        if (!detailedMetrics.isEmpty()) {
+            serializer.startTag(null, DETAIL_TAG);
+            for (Metric elem : detailedMetrics) {
+                elem.serialize(serializer);
             }
+            serializer.endTag(null, DETAIL_TAG);
         }
-        return reportLog;
     }
 
     /**
-     * @return a String representation of this report or null if not collected
+     * Parses a {@link ReportLog} from the given string.
+     * @throws XmlPullParserException
+     * @throws IOException
      */
-    protected String toEncodedString() {
-        if ((mSummary == null) && mDetails.isEmpty()) {
-            // just return empty string
-            return null;
+    public static ReportLog parse(String result) throws XmlPullParserException, IOException {
+        if (result == null || result.trim().isEmpty()) {
+            throw new IllegalArgumentException("Metrics string was empty");
         }
-        StringBuilder builder = new StringBuilder();
-        builder.append(mSummary.toEncodedString());
-        builder.append(SUMMARY_SEPARATOR);
-        for (Result result : mDetails) {
-            builder.append(result.toEncodedString());
-            builder.append(LOG_SEPARATOR);
-        }
-        // delete the last separator
-        if (builder.length() >= LOG_SEPARATOR.length()) {
-            builder.delete(builder.length() - LOG_SEPARATOR.length(), builder.length());
-        }
-        return builder.toString();
+        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+        XmlPullParser parser = factory.newPullParser();
+        parser.setInput(new ByteArrayInputStream(result.getBytes(ENCODING)), ENCODING);
+        parser.nextTag();
+        return parse(parser);
     }
+
+    /**
+     * Parses a {@link ReportLog} from the given XML parser.
+     * @param parser
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    public static ReportLog parse(XmlPullParser parser) throws XmlPullParserException, IOException {
+        parser.require(XmlPullParser.START_TAG, null, SUMMARY_TAG);
+        parser.nextTag();
+        ReportLog report = new ReportLog();
+        report.setSummary(Metric.parse(parser));
+        parser.nextTag();
+        parser.require(XmlPullParser.END_TAG, null, SUMMARY_TAG);
+        try {
+            parser.nextTag();
+        } catch (XmlPullParserException e) {
+            // Report doesn't have any details, it's ok
+            return report;
+        }
+        if (parser.getName().equals(DETAIL_TAG)) {
+            while (parser.nextTag() == XmlPullParser.START_TAG) {
+                report.addMetric(Metric.parse(parser));
+            }
+            parser.require(XmlPullParser.END_TAG, null, DETAIL_TAG);
+        }
+        return report;
+    }
+
 }
diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
new file mode 100644
index 0000000..c4fcfc6
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Handles conversion of results to/from files.
+ */
+public class ResultHandler {
+
+    private static final String ENCODING = "UTF-8";
+    private static final String TYPE = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer";
+    private static final String NS = null;
+    private static final String RESULT_FILE_VERSION = "5.0";
+    /* package */ static final String TEST_RESULT_FILE_NAME = "test_result.xml";
+
+    // XML constants
+    private static final String ABI_ATTR = "abi";
+    private static final String BUGREPORT_TAG = "BugReport";
+    private static final String BUILD_TAG = "Build";
+    private static final String CASE_TAG = "TestCase";
+    private static final String DEVICES_ATTR = "devices";
+    private static final String END_TIME_ATTR = "end";
+    private static final String FAILED_ATTR = "failed";
+    private static final String FAILURE_TAG = "Failure";
+    private static final String HOST_NAME_ATTR = "host_name";
+    private static final String JAVA_VENDOR_ATTR = "java_vendor";
+    private static final String JAVA_VERSION_ATTR = "java_version";
+    private static final String LOGCAT_TAG = "Logcat";
+    private static final String MESSAGE_ATTR = "message";
+    private static final String MODULE_TAG = "Module";
+    private static final String NAME_ATTR = "name";
+    private static final String NOT_EXECUTED_ATTR = "not_executed";
+    private static final String OS_ARCH_ATTR = "os_arch";
+    private static final String OS_NAME_ATTR = "os_name";
+    private static final String OS_VERSION_ATTR = "os_version";
+    private static final String PASS_ATTR = "pass";
+    private static final String REPORT_VERSION_ATTR = "report_version";
+    private static final String REFERENCE_URL_ATTR = "reference_url";
+    private static final String RESULT_ATTR = "result";
+    private static final String RESULT_TAG = "Result";
+    private static final String RUNTIME_ATTR = "runtime";
+    private static final String SCREENSHOT_TAG = "Screenshot";
+    private static final String STACK_TAG = "StackTrace";
+    private static final String START_TIME_ATTR = "start";
+    private static final String SUITE_NAME_ATTR = "suite_name";
+    private static final String SUITE_PLAN_ATTR = "suite_plan";
+    private static final String SUITE_VERSION_ATTR = "suite_version";
+    private static final String SUMMARY_TAG = "Summary";
+    private static final String TEST_TAG = "Test";
+
+    /**
+     * @param resultsDir
+     */
+    public static List<IInvocationResult> getResults(File resultsDir) {
+        List<IInvocationResult> results = new ArrayList<>();
+        File[] files = resultsDir.listFiles();
+        if (files == null || files.length == 0) {
+            // No results, just return the empty list
+            return results;
+        }
+        for (File resultDir : files) {
+            if (!resultDir.isDirectory()) {
+                continue;
+            }
+            try {
+                File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
+                if (!resultFile.exists()) {
+                    continue;
+                }
+                IInvocationResult invocation = new InvocationResult(resultDir);
+                XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+                XmlPullParser parser = factory.newPullParser();
+                parser.setInput(new FileReader(resultFile));
+                parser.nextTag();
+                parser.require(XmlPullParser.START_TAG, NS, RESULT_TAG);
+                invocation.setStartTime(Long.valueOf(
+                        parser.getAttributeValue(NS, START_TIME_ATTR)));
+                invocation.setTestPlan(parser.getAttributeValue(NS, SUITE_PLAN_ATTR));
+                String deviceList = parser.getAttributeValue(NS, DEVICES_ATTR);
+                for (String device : deviceList.split(",")) {
+                    invocation.addDeviceSerial(device);
+                }
+                parser.nextTag();
+                parser.require(XmlPullParser.START_TAG, NS, BUILD_TAG);
+                // TODO(stuartscott): may want to reload these incase the retry was done with
+                // --skip-device-info flag
+                parser.nextTag();
+                parser.require(XmlPullParser.END_TAG, NS, BUILD_TAG);
+                parser.nextTag();
+                parser.require(XmlPullParser.START_TAG, NS, SUMMARY_TAG);
+                parser.nextTag();
+                parser.require(XmlPullParser.END_TAG, NS, SUMMARY_TAG);
+                while (parser.nextTag() == XmlPullParser.START_TAG) {
+                    parser.require(XmlPullParser.START_TAG, NS, MODULE_TAG);
+                    String name = parser.getAttributeValue(NS, NAME_ATTR);
+                    String abi = parser.getAttributeValue(NS, ABI_ATTR);
+                    String id = AbiUtils.createId(abi, name);
+                    IModuleResult module = invocation.getOrCreateModule(id);
+                    while (parser.nextTag() == XmlPullParser.START_TAG) {
+                        parser.require(XmlPullParser.START_TAG, NS, CASE_TAG);
+                        String caseName = parser.getAttributeValue(NS, NAME_ATTR);
+                        ICaseResult testCase = module.getOrCreateResult(caseName);
+                        while (parser.nextTag() == XmlPullParser.START_TAG) {
+                            parser.require(XmlPullParser.START_TAG, NS, TEST_TAG);
+                            String testName = parser.getAttributeValue(NS, NAME_ATTR);
+                            ITestResult test = testCase.getOrCreateResult(testName);
+                            String result = parser.getAttributeValue(NS, RESULT_ATTR);
+                            test.setResultStatus(TestStatus.getStatus(result));
+                            if (parser.nextTag() == XmlPullParser.START_TAG) {
+                                if (parser.getName().equals(FAILURE_TAG)) {
+                                    test.setMessage(parser.getAttributeValue(NS, MESSAGE_ATTR));
+                                    if (parser.nextTag() == XmlPullParser.START_TAG) {
+                                        parser.require(XmlPullParser.START_TAG, NS, STACK_TAG);
+                                        test.setStackTrace(parser.nextText());
+                                        parser.require(XmlPullParser.END_TAG, NS, STACK_TAG);
+                                        parser.nextTag();
+                                    }
+                                    parser.require(XmlPullParser.END_TAG, NS, FAILURE_TAG);
+                                    parser.nextTag();
+                                } else if (parser.getName().equals(BUGREPORT_TAG)) {
+                                    test.setBugReport(parser.nextText());
+                                    parser.nextTag();
+                                } else if (parser.getName().equals(LOGCAT_TAG)) {
+                                    test.setLog(parser.nextText());
+                                    parser.nextTag();
+                                } else if (parser.getName().equals(SCREENSHOT_TAG)) {
+                                    test.setScreenshot(parser.nextText());
+                                    parser.nextTag();
+                                } else {
+                                    test.setReportLog(ReportLog.parse(parser));
+                                    parser.nextTag();
+                                }
+                            }
+                            parser.require(XmlPullParser.END_TAG, NS, TEST_TAG);
+                        }
+                        parser.require(XmlPullParser.END_TAG, NS, CASE_TAG);
+                    }
+                    parser.require(XmlPullParser.END_TAG, NS, MODULE_TAG);
+                }
+                parser.require(XmlPullParser.END_TAG, NS, RESULT_TAG);
+                results.add(invocation);
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return results;
+    }
+
+    /**
+     * @param result
+     * @param resultDir
+     * @param startTime
+     * @param referenceUrl A nullable string that can contain a URL to a related data
+     * @return The result file created.
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    public static File writeResults(String suiteName, String suiteVersion, String suitePlan,
+            IInvocationResult result, File resultDir, long startTime, long endTime,
+                    String referenceUrl) throws IOException, XmlPullParserException {
+        int passed = result.countResults(TestStatus.PASS);
+        int failed = result.countResults(TestStatus.FAIL);
+        int notExecuted = result.countResults(TestStatus.NOT_EXECUTED);
+        File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
+        OutputStream stream = new FileOutputStream(resultFile);
+        XmlSerializer serializer = XmlPullParserFactory.newInstance(TYPE, null).newSerializer();
+        serializer.setOutput(stream, ENCODING);
+        serializer.startDocument(ENCODING, false);
+        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        serializer.processingInstruction(
+                "xml-stylesheet type=\"text/xsl\" href=\"compatibility-result.xsl\"");
+        serializer.startTag(NS, RESULT_TAG);
+        serializer.attribute(NS, START_TIME_ATTR, String.valueOf(startTime));
+        serializer.attribute(NS, END_TIME_ATTR, String.valueOf(endTime));
+        serializer.attribute(NS, SUITE_NAME_ATTR, suiteName);
+        serializer.attribute(NS, SUITE_VERSION_ATTR, suiteVersion);
+        serializer.attribute(NS, SUITE_PLAN_ATTR, suitePlan);
+        serializer.attribute(NS, REPORT_VERSION_ATTR, RESULT_FILE_VERSION);
+        if (referenceUrl != null) {
+            serializer.attribute(NS, REFERENCE_URL_ATTR, referenceUrl);
+        }
+
+        // Device Info
+        Set<String> devices = result.getDeviceSerials();
+        StringBuilder deviceList = new StringBuilder();
+        boolean first = true;
+        for (String device : devices) {
+            if (first) {
+                first = false;
+            } else {
+                deviceList.append(",");
+            }
+            deviceList.append(device);
+        }
+        serializer.attribute(NS, DEVICES_ATTR, deviceList.toString());
+
+        // Host Info
+        String hostName = "";
+        try {
+            hostName = InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException ignored) {}
+        serializer.attribute(NS, HOST_NAME_ATTR, hostName);
+        serializer.attribute(NS, OS_NAME_ATTR, System.getProperty("os.name"));
+        serializer.attribute(NS, OS_VERSION_ATTR, System.getProperty("os.version"));
+        serializer.attribute(NS, OS_ARCH_ATTR, System.getProperty("os.arch"));
+        serializer.attribute(NS, JAVA_VENDOR_ATTR, System.getProperty("java.vendor"));
+        serializer.attribute(NS, JAVA_VERSION_ATTR, System.getProperty("java.version"));
+
+        // Build Info
+        serializer.startTag(NS, BUILD_TAG);
+        for (Entry<String, String> entry : result.getBuildInfo().entrySet()) {
+            serializer.attribute(NS, entry.getKey(), entry.getValue());
+        }
+        serializer.endTag(NS, BUILD_TAG);
+
+        // Summary
+        serializer.startTag(NS, SUMMARY_TAG);
+        serializer.attribute(NS, PASS_ATTR, Integer.toString(passed));
+        serializer.attribute(NS, FAILED_ATTR, Integer.toString(failed));
+        serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(notExecuted));
+        serializer.endTag(NS, SUMMARY_TAG);
+
+        // Results
+        for (IModuleResult module : result.getModules()) {
+            serializer.startTag(NS, MODULE_TAG);
+            serializer.attribute(NS, NAME_ATTR, module.getName());
+            serializer.attribute(NS, ABI_ATTR, module.getAbi());
+            serializer.attribute(NS, RUNTIME_ATTR, String.valueOf(module.getRuntime()));
+            for (ICaseResult cr : module.getResults()) {
+                serializer.startTag(NS, CASE_TAG);
+                serializer.attribute(NS, NAME_ATTR, cr.getName());
+                for (ITestResult r : cr.getResults()) {
+                    serializer.startTag(NS, TEST_TAG);
+                    serializer.attribute(NS, RESULT_ATTR, r.getResultStatus().getValue());
+                    serializer.attribute(NS, NAME_ATTR, r.getName());
+                    String message = r.getMessage();
+                    if (message != null) {
+                        serializer.startTag(NS, FAILURE_TAG);
+                        serializer.attribute(NS, MESSAGE_ATTR, message);
+                        String stackTrace = r.getStackTrace();
+                        if (stackTrace != null) {
+                            serializer.startTag(NS, STACK_TAG);
+                            serializer.text(stackTrace);
+                            serializer.endTag(NS, STACK_TAG);
+                        }
+                        serializer.endTag(NS, FAILURE_TAG);
+                    }
+                    String bugreport = r.getBugReport();
+                    if (bugreport != null) {
+                        serializer.startTag(NS, BUGREPORT_TAG);
+                        serializer.text(bugreport);
+                        serializer.endTag(NS, BUGREPORT_TAG);
+                    }
+                    String logcat = r.getLog();
+                    if (logcat != null) {
+                        serializer.startTag(NS, LOGCAT_TAG);
+                        serializer.text(logcat);
+                        serializer.endTag(NS, LOGCAT_TAG);
+                    }
+                    String screenshot = r.getScreenshot();
+                    if (screenshot != null) {
+                        serializer.startTag(NS, SCREENSHOT_TAG);
+                        serializer.text(screenshot);
+                        serializer.endTag(NS, SCREENSHOT_TAG);
+                    }
+                    ReportLog report = r.getReportLog();
+                    if (report != null) {
+                        ReportLog.serialize(serializer, report);
+                    }
+                    serializer.endTag(NS, TEST_TAG);
+                }
+                serializer.endTag(NS, CASE_TAG);
+            }
+            serializer.endTag(NS, MODULE_TAG);
+        }
+        serializer.endDocument();
+        return resultFile;
+    }
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/ResultType.java b/common/util/src/com/android/compatibility/common/util/ResultType.java
index 779c6d0..9d0a5fa 100644
--- a/common/util/src/com/android/compatibility/common/util/ResultType.java
+++ b/common/util/src/com/android/compatibility/common/util/ResultType.java
@@ -30,9 +30,16 @@
     WARNING;
 
     /**
-     * Return string used in the XML report
+     * @return a string to be used in the report.
      */
-    public String getXmlString() {
+    public String toReportString() {
         return name().toLowerCase();
     }
+
+    /**
+     * Returns a {@link ResultType} given a string from the report.
+     */
+    public static ResultType parseReportString(String value) {
+        return ResultType.valueOf(value.toUpperCase());
+    }
 }
diff --git a/common/util/src/com/android/compatibility/common/util/ResultUnit.java b/common/util/src/com/android/compatibility/common/util/ResultUnit.java
index f38ddae..5b082f9 100644
--- a/common/util/src/com/android/compatibility/common/util/ResultUnit.java
+++ b/common/util/src/com/android/compatibility/common/util/ResultUnit.java
@@ -40,10 +40,16 @@
     SCORE;
 
     /**
-     * Return string used in the XML report
+     * @return a string to be used in the report.
      */
-    public String getXmlString() {
+    public String toReportString() {
         return name().toLowerCase();
     }
-}
 
+    /**
+     * Returns a {@link ResultUnit} given a string from the report.
+     */
+    public static ResultUnit parseReportString(String value) {
+        return ResultUnit.valueOf(value.toUpperCase());
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/ResultUploader.java b/common/util/src/com/android/compatibility/common/util/ResultUploader.java
new file mode 100644
index 0000000..ff8d156
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/ResultUploader.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * Uploads a result through a HTTP POST multipart/form-data request containing
+ * the test result XML.
+ */
+public class ResultUploader {
+
+    private static final int RESULT_XML_BYTES = 500 * 1024;
+
+    /* package */ MultipartForm mMultipartForm;
+
+    public ResultUploader(String serverUrl, String suiteName) {
+        mMultipartForm = new MultipartForm(serverUrl).addFormValue("suite", suiteName);
+    }
+
+    /**
+     * Uploads the given file to the server.
+     *
+     * @param reportFile The file to upload.
+     * @param referenceUrl A reference url to use.
+     * @throws IOException
+     */
+    public void uploadResult(File reportFile, String referenceUrl) throws IOException {
+        InputStream input = new FileInputStream(reportFile);
+        try {
+            byte[] data = getBytes(input);
+            mMultipartForm.addFormFile("result-xml", "test-result.xml.gz", data);
+            if (referenceUrl == null || referenceUrl.trim().isEmpty()) {
+                mMultipartForm.addFormValue("reference-url", referenceUrl);
+            }
+            mMultipartForm.submit();
+        } finally {
+            input.close();
+        }
+    }
+
+    private static byte[] getBytes(InputStream input) throws IOException {
+        ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(RESULT_XML_BYTES);
+        GZIPOutputStream gzipOutput = new GZIPOutputStream(byteOutput);
+        byte[] buffer = new byte[1024];
+        int count;
+        while ((count = input.read(buffer)) > 0) {
+            gzipOutput.write(buffer, 0, count);
+        }
+        gzipOutput.close();
+        return byteOutput.toByteArray();
+    }
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/Stat.java b/common/util/src/com/android/compatibility/common/util/Stat.java
index 8bf9bf7..9748440 100644
--- a/common/util/src/com/android/compatibility/common/util/Stat.java
+++ b/common/util/src/com/android/compatibility/common/util/Stat.java
@@ -22,6 +22,10 @@
  * Utilities for doing statistics
  */
 public class Stat {
+    /**
+     * Private constructor for static class.
+     */
+    private Stat() {}
 
     /**
      * Collection of statistical propertirs like average, max, min, and stddev
@@ -48,10 +52,8 @@
         double average = data[0];
         double min = data[0];
         double max = data[0];
-        double eX2 = data[0] * data[0]; // will become E[X^2]
         for (int i = 1; i < data.length; i++) {
             average += data[i];
-            eX2 += data[i] * data[i];
             if (data[i] > max) {
                 max = data[i];
             }
@@ -60,9 +62,13 @@
             }
         }
         average /= data.length;
-        eX2 /= data.length;
-        // stddev = sqrt(E[X^2] - (E[X])^2)
-        double stddev = Math.sqrt(eX2 - average * average);
+        double sumOfSquares = 0.0;
+        for (int i = 0; i < data.length; i++) {
+            double diff = average - data[i];
+            sumOfSquares += diff * diff;
+        }
+        double variance = sumOfSquares / (data.length - 1);
+        double stddev = Math.sqrt(variance);
         return new StatResult(average, min, max, stddev, data.length);
     }
 
@@ -84,37 +90,16 @@
         double thresholdMin = median * (1.0 - rejectionThreshold);
         double thresholdMax = median * (1.0 + rejectionThreshold);
 
-        double average = 0.0;
-        double min = median;
-        double max = median;
-        double eX2 = 0.0; // will become E[X^2]
-        int validDataCounter = 0;
+        double[] validData = new double[data.length];
+        int index = 0;
         for (int i = 0; i < data.length; i++) {
             if ((data[i] > thresholdMin) && (data[i] < thresholdMax)) {
-                validDataCounter++;
-                average += data[i];
-                eX2 += data[i] * data[i];
-                if (data[i] > max) {
-                    max = data[i];
-                }
-                if (data[i] < min) {
-                    min = data[i];
-                }
+                validData[index] = data[i];
+                index++;
             }
             // TODO report rejected data
         }
-        double stddev;
-        if (validDataCounter > 0) {
-            average /= validDataCounter;
-            eX2 /= validDataCounter;
-            // stddev = sqrt(E[X^2] - (E[X])^2)
-            stddev = Math.sqrt(eX2 - average * average);
-        } else { // both median is showing too much diff
-            average = median;
-            stddev = 0; // don't care
-        }
-
-        return new StatResult(average, min, max, stddev, validDataCounter);
+        return getStat(Arrays.copyOf(validData, index));
     }
 
     /**
@@ -159,7 +144,6 @@
      * timeInSec with 0 value will be changed to small value to prevent divide by zero.
      * @param change total change of quality for the given duration timeInMSec.
      * @param timeInMSec
-     * @return
      */
     public static double calcRatePerSec(double change, double timeInMSec) {
         if (timeInMSec == 0) {
@@ -185,4 +169,14 @@
         return result;
     }
 
+    /**
+     * Get the value of the 95th percentile using nearest rank algorithm.
+     */
+    public static double get95PercentileValue(double[] values) {
+        Arrays.sort(values);
+        // zero-based array index
+        int index = (int) Math.round(values.length * 0.95 + .5) - 1;
+        return values[index];
+    }
+
 }
diff --git a/common/util/src/com/android/compatibility/common/util/TestFilter.java b/common/util/src/com/android/compatibility/common/util/TestFilter.java
new file mode 100644
index 0000000..78b68cf
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/TestFilter.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+/**
+ * Represents a filter for including and excluding tests.
+ */
+public class TestFilter {
+
+    private final String mAbi;
+    private final String mName;
+    private final String mTest;
+
+    /**
+     * Builds a new {@link TestFilter} from the given string. Filters can be in one of four forms,
+     * the instance will be initialized as;
+     * -"name"              -> abi = null, name = "name", test = null
+     * -"name" "test"       -> abi = null, name = "name", test = "test"
+     * -"abi" "name"        -> abi = "abi", name = "name", test = null
+     * -"abi" "name" test"  -> abi = "abi", name = "name", test = "test"
+     *
+     * @param filter the filter to parse
+     * @return the {@link TestFilter}
+     */
+    public static TestFilter createFrom(String filter) {
+        String[] parts = filter.split(" ");
+        String abi = null, name = null, test = null;
+        // Either:
+        // <name>
+        // <name> <test>
+        // <abi> <name>
+        // <abi> <name> <test>
+        if (parts.length == 1) {
+            name = parts[0];
+        } else if (parts.length == 2) {
+            if (AbiUtils.isAbiSupportedByCompatibility(parts[0])) {
+                abi = parts[0];
+                name = parts[1];
+            } else {
+                name = parts[0];
+                test = parts[1];
+            }
+        } else if (parts.length == 3){
+            abi = parts[0];
+            name = parts[1];
+            test = parts[2];
+        } else {
+            throw new IllegalArgumentException(String.format("Could not parse filter: %s", filter));
+        }
+        return new TestFilter(abi, name, test);
+    }
+
+    /**
+     * Creates a new {@link TestFilter} from the given parts.
+     *
+     * @param abi The ABI must be supported {@link AbiUtils#isAbiSupportedByCompatibility(String)}
+     * @param name The module's name
+     * @param test The test's identifier eg <package>.<class>#<method>
+     */
+    public TestFilter(String abi, String name, String test) {
+        mAbi = abi;
+        mName = name;
+        mTest = test;
+    }
+
+    /**
+     * Returns a String representation of this filter. This function is the inverse of
+     * {@link TestFilter#createFrom(String)}.
+     *
+     * For a valid filter f;
+     * <pre>
+     * {@code
+     * new TestFilter(f).toString().equals(f)
+     * }
+     * </pre>
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        if (mAbi != null) {
+            sb.append(mAbi);
+            sb.append(" ");
+        }
+        if (mName != null) {
+            sb.append(mName);
+        }
+        if (mTest != null) {
+            sb.append(" ");
+            sb.append(mTest);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * @return the abi of this filter, or null if not specified.
+     */
+    public String getAbi() {
+        return mAbi;
+    }
+
+    /**
+     * @return the module name of this filter, or null if not specified.
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * @return the test identifier of this filter, or null if not specified.
+     */
+    public String getTest() {
+        return mTest;
+    }
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/TestResult.java b/common/util/src/com/android/compatibility/common/util/TestResult.java
new file mode 100644
index 0000000..03aaca29
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/TestResult.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+/**
+ * Represents a single test result.
+ */
+public class TestResult implements ITestResult {
+
+    private final ICaseResult mParent;
+    private final String mTestName;
+    private TestStatus mResult;
+    private String mMessage;
+    private String mStackTrace;
+    private ReportLog mReport;
+    private String mBugReport;
+    private String mLog;
+    private String mScreenshot;
+
+    /**
+     * Create a {@link TestResult} for the given test name.
+     */
+    public TestResult(ICaseResult parent, String name) {
+        mParent = parent;
+        mTestName = name;
+        reset();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getName() {
+        return mTestName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getFullName() {
+        return String.format("%s#%s", mParent.getName(), getName());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public TestStatus getResultStatus() {
+        return mResult;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setResultStatus(TestStatus status) {
+        mResult = status;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getMessage() {
+        return mMessage;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setMessage(String message) {
+        mMessage = message;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getStackTrace() {
+        return mStackTrace;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setStackTrace(String stackTrace) {
+        mStackTrace = sanitizeStackTrace(stackTrace);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ReportLog getReportLog() {
+        return mReport;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setReportLog(ReportLog report) {
+        mReport = report;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getBugReport() {
+        return mBugReport;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBugReport(String path) {
+        mBugReport = path;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getLog() {
+        return mLog;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setLog(String path) {
+        mLog = path;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getScreenshot() {
+        return mScreenshot;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setScreenshot(String path) {
+        mScreenshot = path;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void failed(String trace) {
+        setResultStatus(TestStatus.FAIL);
+        int index = trace.indexOf('\n');
+        if (index < 0) {
+            // Trace is a single line, just set the message to be the same as the stacktrace.
+            setMessage(trace);
+        } else {
+            setMessage(trace.substring(0, index));
+        }
+        setStackTrace(trace);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void passed(ReportLog report) {
+        if (!getResultStatus().equals(TestStatus.FAIL)) {
+            setResultStatus(TestStatus.PASS);
+            if (report != null) {
+                setReportLog(report);
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void reset() {
+        mResult = TestStatus.NOT_EXECUTED;
+        mMessage = null;
+        mStackTrace = null;
+        mReport = null;
+        mBugReport = null;
+        mLog = null;
+        mScreenshot = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int compareTo(ITestResult another) {
+        return getName().compareTo(another.getName());
+    }
+
+    /**
+     * Strip out any invalid XML characters that might cause the report to be unviewable.
+     * http://www.w3.org/TR/REC-xml/#dt-character
+     */
+    static String sanitizeStackTrace(String trace) {
+        if (trace != null) {
+            return trace.replaceAll("[^\\u0009\\u000A\\u000D\\u0020-\\uD7FF\\uE000-\\uFFFD]", "");
+        } else {
+            return null;
+        }
+    }
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/TestStatus.java b/common/util/src/com/android/compatibility/common/util/TestStatus.java
new file mode 100644
index 0000000..766e4d2
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/TestStatus.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+/**
+ * An enum of possible test statuses.
+ */
+public enum TestStatus {
+    PASS("pass"),
+    FAIL("fail"),
+    NOT_EXECUTED("not_executed");
+
+    private String mValue;
+
+    private TestStatus(String storedValue) {
+        mValue = storedValue;
+    }
+
+    /**
+     * Get the String representation of this test status that should be stored in
+     * xml
+     */
+    public String getValue() {
+       return mValue;
+    }
+
+    /**
+     * Find the {@link TestStatus} corresponding to given string value
+     * <p/>
+     * Performs a case insensitive search
+     *
+     * @param value
+     * @return the {@link TestStatus} or <code>null</code> if it could not be found
+     */
+    static TestStatus getStatus(String  value) {
+        for (TestStatus status : TestStatus.values()) {
+            if (value.compareToIgnoreCase(status.getValue()) == 0) {
+                return status;
+            }
+        }
+        return null;
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/TestSuiteFilter.java b/common/util/src/com/android/compatibility/common/util/TestSuiteFilter.java
new file mode 100644
index 0000000..e498c17
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/TestSuiteFilter.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Set;
+
+public class TestSuiteFilter {
+
+    private TestSuiteFilter() {}
+
+    public static TestSuite createSuite(List<Class<?>> classes, Set<String> includes,
+            Set<String> excludes) {
+        return new FilterableTestSuite(classes, includes, excludes);
+    }
+
+    /**
+     * A {@link TestSuite} that can filter which tests run, given the include and exclude filters.
+     *
+     * This had to be private inner class because the test runner would find it and think it was a
+     * suite of tests, but it has no tests in it, causing a crash.
+     */
+    private static class FilterableTestSuite extends TestSuite {
+
+        private Set<String> mIncludes;
+        private Set<String> mExcludes;
+
+        public FilterableTestSuite(List<Class<?>> classes, Set<String> includes,
+                Set<String> excludes) {
+            super(classes.toArray(new Class<?>[classes.size()]));
+            mIncludes = includes;
+            mExcludes = excludes;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public int countTestCases() {
+            return countTests(this);
+        }
+
+        private int countTests(Test test) {
+            if (test instanceof TestSuite) {
+                // If the test is a suite it could contain multiple tests, these need to be split
+                // out into separate tests so they can be filtered
+                TestSuite suite = (TestSuite) test;
+                Enumeration<Test> enumerator = suite.tests();
+                int count = 0;
+                while (enumerator.hasMoreElements()) {
+                    count += countTests(enumerator.nextElement());
+                }
+                return count;
+            } else if (shouldRun(test)) {
+                return 1;
+            }
+            return 0;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void runTest(Test test, TestResult result) {
+            runTests(test, result);
+        }
+
+        private void runTests(Test test, TestResult result) {
+            if (test instanceof TestSuite) {
+                // If the test is a suite it could contain multiple tests, these need to be split
+                // out into separate tests so they can be filtered
+                TestSuite suite = (TestSuite) test;
+                Enumeration<Test> enumerator = suite.tests();
+                while (enumerator.hasMoreElements()) {
+                    runTests(enumerator.nextElement(), result);
+                }
+            } else if (shouldRun(test)) {
+                test.run(result);
+            }
+        }
+
+        private boolean shouldRun(Test test) {
+            String fullName = test.toString();
+            String[] parts = fullName.split("[\\(\\)]");
+            String className = parts[1];
+            String methodName = String.format("%s#%s", className, parts[0]);
+            int index = className.lastIndexOf('.');
+            String packageName = index < 0 ? "" : className.substring(0, index);
+
+            if (mExcludes.contains(packageName)) {
+                // Skip package because it was excluded
+                return false;
+            }
+            if (mExcludes.contains(className)) {
+                // Skip class because it was excluded
+                return false;
+            }
+            if (mExcludes.contains(methodName)) {
+                // Skip method because it was excluded
+                return false;
+            }
+            return mIncludes.isEmpty()
+                    || mIncludes.contains(methodName)
+                    || mIncludes.contains(className)
+                    || mIncludes.contains(packageName);
+        }
+    }
+}
diff --git a/common/util/tests/Android.mk b/common/util/tests/Android.mk
new file mode 100644
index 0000000..0e0af50
--- /dev/null
+++ b/common/util/tests/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := junit kxml2-2.3.0 tradefed-prebuilt compatibility-common-util-hostsidelib
+
+LOCAL_MODULE := compatibility-common-util-tests
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/util/tests/run_tests.sh b/common/util/tests/run_tests.sh
new file mode 100755
index 0000000..0045014
--- /dev/null
+++ b/common/util/tests/run_tests.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# Copyright (C) 2015 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.
+
+CTS_DIR=$(dirname ${0})/../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+    compatibility-common-util-hostsidelib\
+    compatibility-common-util-tests\
+    compatibility-host-util\
+    compatibility-host-util-tests\
+    compatibility-mock-tradefed\
+    compatibility-tradefed-tests"
+
+run_tests "com.android.compatibility.common.util.UnitTests" "${JARS}" "${@}"
+
diff --git a/common/util/tests/src/com/android/compatibility/common/util/AbiUtilsTest.java b/common/util/tests/src/com/android/compatibility/common/util/AbiUtilsTest.java
new file mode 100644
index 0000000..567da54
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/AbiUtilsTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.compatibility.common.util;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link AbiUtils}
+ */
+public class AbiUtilsTest extends TestCase {
+
+    private static final String MODULE_NAME = "ModuleName";
+    private static final String ABI_NAME = "mips64";
+    private static final String ABI_FLAG = "--abi mips64 ";
+    private static final String ABI_ID = "mips64 ModuleName";
+
+    public void testCreateAbiFlag() {
+        String flag = AbiUtils.createAbiFlag(ABI_NAME);
+        assertEquals("Incorrect flag created", ABI_FLAG, flag);
+    }
+
+    public void testCreateId() {
+        String id = AbiUtils.createId(ABI_NAME, MODULE_NAME);
+        assertEquals("Incorrect id created", ABI_ID, id);
+    }
+
+    public void testParseId() {
+        String[] parts = AbiUtils.parseId(ABI_ID);
+        assertEquals("Wrong size array", 2, parts.length);
+        assertEquals("Wrong abi name", ABI_NAME, parts[0]);
+        assertEquals("Wrong module name", MODULE_NAME, parts[1]);
+    }
+
+    public void testParseName() {
+        String name = AbiUtils.parseTestName(ABI_ID);
+        assertEquals("Incorrect module name", MODULE_NAME, name);
+    }
+
+    public void testParseAbi() {
+        String abi = AbiUtils.parseAbi(ABI_ID);
+        assertEquals("Incorrect abi name", ABI_NAME, abi);
+    }
+
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/CaseResultTest.java b/common/util/tests/src/com/android/compatibility/common/util/CaseResultTest.java
new file mode 100644
index 0000000..ae29597
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/CaseResultTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link CaseResult}
+ */
+public class CaseResultTest extends TestCase {
+
+    private static final String CLASS = "android.test.FoorBar";
+    private static final String METHOD_1 = "testBlah1";
+    private static final String METHOD_2 = "testBlah2";
+    private static final String METHOD_3 = "testBlah3";
+    private static final String MESSAGE = "Something small is not alright";
+    private static final String STACK_TRACE = "Something small is not alright\n " +
+            "at four.big.insects.Marley.sing(Marley.java:10)";
+    private CaseResult mResult;
+
+    @Override
+    public void setUp() throws Exception {
+        mResult = new CaseResult(CLASS);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mResult = null;
+    }
+
+    public void testAccessors() throws Exception {
+        assertEquals("Incorrect case name", CLASS, mResult.getName());
+    }
+
+    public void testResultCreation() throws Exception {
+        ITestResult testResult = mResult.getOrCreateResult(METHOD_1);
+        // Should create one
+        assertEquals("Expected one result", 1, mResult.getResults().size());
+        assertTrue("Expected test result", mResult.getResults().contains(testResult));
+        // Should not create another one
+        ITestResult testResult2 = mResult.getOrCreateResult(METHOD_1);
+        assertEquals("Expected the same result", testResult, testResult2);
+        assertEquals("Expected one result", 1, mResult.getResults().size());
+    }
+
+    public void testResultReporting() throws Exception {
+        ITestResult testResult = mResult.getOrCreateResult(METHOD_1);
+        testResult.failed(STACK_TRACE);
+        assertEquals("Expected status to be set", TestStatus.FAIL, testResult.getResultStatus());
+        assertEquals("Expected message to be set", MESSAGE, testResult.getMessage());
+        assertEquals("Expected stack to be set", STACK_TRACE, testResult.getStackTrace());
+        testResult = mResult.getOrCreateResult(METHOD_2);
+        testResult.passed(null);
+        assertEquals("Expected status to be set", TestStatus.PASS, testResult.getResultStatus());
+        assertEquals("Expected two results", 2, mResult.getResults().size());
+    }
+
+    public void testCountResults() throws Exception {
+        mResult.getOrCreateResult(METHOD_1).failed(STACK_TRACE);
+        mResult.getOrCreateResult(METHOD_2).failed(STACK_TRACE);
+        mResult.getOrCreateResult(METHOD_3).passed(null);
+        assertEquals("Expected two failures", 2, mResult.countResults(TestStatus.FAIL));
+        assertEquals("Expected one pass", 1, mResult.countResults(TestStatus.PASS));
+    }
+}
\ No newline at end of file
diff --git a/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java b/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
new file mode 100644
index 0000000..6d6ba2d
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import junit.framework.TestCase;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Unit tests for {@link DynamicConfig}
+ */
+public class DynamicConfigTest extends TestCase {
+    private static final String correctConfig =
+            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+            "<DynamicConfig>\n" +
+            "    <Config key=\"test-config-1\">test config 1</Config>\n" +
+            "    <Config key=\"test-config-2\">testconfig2</Config>\n" +
+            "    <ConfigList key=\"config-list\">\n" +
+            "        <Item>config0</Item>\n" +
+            "        <Item>config1</Item>\n" +
+            "        <Item>config2</Item>\n" +
+            "        <Item>config3</Item>\n" +
+            "        <Item>config4</Item>\n" +
+            "    </ConfigList>\n" +
+            "    <ConfigList key=\"config-list-2\">\n" +
+            "        <Item>A</Item>\n" +
+            "        <Item>B</Item>\n" +
+            "        <Item>C</Item>\n" +
+            "        <Item>D</Item>\n" +
+            "        <Item>E</Item>\n" +
+            "    </ConfigList>\n" +
+            "</DynamicConfig>\n";
+
+    private static final String configWrongNodeName =
+            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+            "<DynamicCsonfig>\n" +  //The node name DynamicConfig is intentionally mistyped
+            "    <Config key=\"test-config-1\">test config 1</Config>\n" +
+            "    <Config key=\"test-config-2\">testconfig2</Config>\n" +
+            "    <ConfigList key=\"config-list\">\n" +
+            "        <Item>Nevermore</Item>\n" +
+            "        <Item>Puck</Item>\n" +
+            "        <Item>Zeus</Item>\n" +
+            "        <Item>Earth Shaker</Item>\n" +
+            "        <Item>Vengeful Spirit</Item>\n" +
+            "    </ConfigList>\n" +
+            "    <ConfigList key=\"config-list-2\">\n" +
+            "        <Item>A</Item>\n" +
+            "        <Item>B</Item>\n" +
+            "        <Item>C</Item>\n" +
+            "        <Item>D</Item>\n" +
+            "        <Item>E</Item>\n" +
+            "    </ConfigList>\n" +
+            "</DynamicConfig>\n";
+
+    public void testCorrectConfig() throws Exception {
+        DynamicConfig config = new DynamicConfig();
+        File file = createFileFromStr(correctConfig);
+        config.initConfigFromXml(file);
+
+        assertEquals("Wrong Config", config.getConfig("test-config-1"), "test config 1");
+        assertEquals("Wrong Config", config.getConfig("test-config-2"), "testconfig2");
+        assertEquals("Wrong Config List", config.getConfigList("config-list").get(0), "config0");
+        assertEquals("Wrong Config List", config.getConfigList("config-list").get(2), "config2");
+        assertEquals("Wrong Config List", config.getConfigList("config-list-2").get(2), "C");
+    }
+
+    public void testConfigWithWrongNodeName() throws Exception {
+        DynamicConfig config = new DynamicConfig();
+        File file = createFileFromStr(configWrongNodeName);
+
+        try {
+            config.initConfigFromXml(file);
+            fail("Cannot detect error when config file has wrong node name");
+        } catch (XmlPullParserException e) {
+            //expected
+        }
+    }
+
+    private File createFileFromStr(String configStr) throws IOException {
+        File file = File.createTempFile("test", "dynamic");
+        FileOutputStream stream = new FileOutputStream(file);
+        stream.write(configStr.getBytes());
+        stream.flush();
+        return file;
+    }
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java b/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java
index 05e69d8..c6f3ec1 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java
@@ -24,6 +24,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
+//TODO(stuartscott): Delete file for v2, ReportLog can serialize itself.
 /**
  * Unit tests for {@link MetricsXmlSerializer}
  */
@@ -32,8 +33,7 @@
     static class LocalReportLog extends ReportLog {}
     private static final double[] VALUES = new double[] {1, 11, 21, 1211, 111221};
     private static final String HEADER = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>";
-    private static final String EXPECTED_XML =
-            HEADER
+    private static final String EXPECTED_XML = HEADER
             + "<Summary message=\"Sample\" scoreType=\"higher_better\" unit=\"byte\">1.0</Summary>"
             + "<Details>"
                     + "<ValueArray source=\"com.android.compatibility.common.util."
@@ -89,4 +89,4 @@
 
         assertEquals(EXPECTED_XML, mByteArrayOutputStream.toString("utf-8"));
     }
-}
+}
\ No newline at end of file
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ModuleResultTest.java b/common/util/tests/src/com/android/compatibility/common/util/ModuleResultTest.java
new file mode 100644
index 0000000..2239ac8
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/ModuleResultTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link ModuleResult}
+ */
+public class ModuleResultTest extends TestCase {
+
+    private static final String NAME = "ModuleName";
+    private static final String ABI = "mips64";
+    private static final String ID = AbiUtils.createId(ABI, NAME);
+    private static final String CLASS = "android.test.FoorBar";
+    private static final String METHOD_1 = "testBlah1";
+    private static final String METHOD_2 = "testBlah2";
+    private static final String METHOD_3 = "testBlah3";
+    private static final String STACK_TRACE = "Something small is not alright\n " +
+            "at four.big.insects.Marley.sing(Marley.java:10)";
+    private ModuleResult mResult;
+
+    @Override
+    public void setUp() throws Exception {
+        mResult = new ModuleResult(ID);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mResult = null;
+    }
+
+    public void testAccessors() throws Exception {
+        assertEquals("Incorrect module ID", ID, mResult.getId());
+        assertEquals("Incorrect module ABI", ABI, mResult.getAbi());
+        assertEquals("Incorrect module name", NAME, mResult.getName());
+    }
+
+    public void testResultCreation() throws Exception {
+        ICaseResult caseResult = mResult.getOrCreateResult(CLASS);
+        // Should create one
+        assertEquals("Expected one result", 1, mResult.getResults().size());
+        assertTrue("Expected test result", mResult.getResults().contains(caseResult));
+        // Should not create another one
+        ICaseResult caseResult2 = mResult.getOrCreateResult(CLASS);
+        assertEquals("Expected the same result", caseResult, caseResult2);
+        assertEquals("Expected one result", 1, mResult.getResults().size());
+    }
+
+    public void testCountResults() throws Exception {
+        ICaseResult testCase = mResult.getOrCreateResult(CLASS);
+        testCase.getOrCreateResult(METHOD_1).failed(STACK_TRACE);
+        testCase.getOrCreateResult(METHOD_2).failed(STACK_TRACE);
+        testCase.getOrCreateResult(METHOD_3).passed(null);
+        assertEquals("Expected two failures", 2, mResult.countResults(TestStatus.FAIL));
+        assertEquals("Expected one pass", 1, mResult.countResults(TestStatus.PASS));
+    }
+}
\ No newline at end of file
diff --git a/common/util/tests/src/com/android/compatibility/common/util/MultipartFormTest.java b/common/util/tests/src/com/android/compatibility/common/util/MultipartFormTest.java
new file mode 100644
index 0000000..dd96308
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/MultipartFormTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.compatibility.common.util;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+/**
+ * Unit tests for {@link MultipartForm}
+ */
+public class MultipartFormTest extends TestCase {
+
+    private static final String SERVER_URL = "http://127.0.0.1:5555";
+    private static final byte[] ZIP_ARRAY = {
+            0xa, 0x2d, 0x2d, 0x43, 0x37, 0x35, 0x49, 0x35, 0x35, 0x75, 0x33, 0x52, 0x33, 0x70, 0x30,
+            0x72, 0x37, 0x33, 0x72, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x44, 0x69,
+            0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x66, 0x6f, 0x72,
+            0x6d, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x3b, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22,
+            0x66, 0x6f, 0x6f, 0x22, 0xa, 0xa, 0x62, 0x61, 0x72, 0xa, 0x2d, 0x2d, 0x43, 0x37, 0x35,
+            0x49, 0x35, 0x35, 0x75, 0x33, 0x52, 0x33, 0x70, 0x30, 0x72, 0x37, 0x33, 0x72, 0xa, 0x43,
+            0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x44, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69,
+            0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x64, 0x61, 0x74,
+            0x61, 0x3b, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x62, 0x6c, 0x61, 0x68, 0x22,
+            0x3b, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x62, 0x6c,
+            0x61, 0x68, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x67, 0x7a, 0x22, 0xa, 0x43, 0x6f, 0x6e, 0x74,
+            0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, 0x70, 0x6c,
+            0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x67, 0x7a, 0x69, 0x70, 0xa,
+            0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66,
+            0x65, 0x72, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x62,
+            0x69, 0x6e, 0x61, 0x72, 0x79, 0xa, 0xa, 0x62, 0x6c, 0x61, 0x68, 0xa, 0x2d, 0x2d, 0x43,
+            0x37, 0x35, 0x49, 0x35, 0x35, 0x75, 0x33, 0x52, 0x33, 0x70, 0x30, 0x72, 0x37, 0x33,
+            0x72, 0x2d, 0x2d, 0xa,
+    };
+
+    public void testContentBody() throws Exception {
+        MultipartForm form = new MultipartForm(SERVER_URL);
+        form.addFormValue("foo", "bar");
+        form.addFormFile("blah", "blah.xml.gz", "blah".getBytes());
+        byte[] data = form.getContentBody();
+        assertTrue("No data", data.length > 0);
+        assertTrue("Wrong data", Arrays.equals(ZIP_ARRAY, data));
+    }
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
index a5f3306..0b4a639 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
@@ -16,8 +16,13 @@
 
 package com.android.compatibility.common.util;
 
+import com.android.compatibility.common.util.ReportLog.Metric;
+
 import junit.framework.TestCase;
 
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.util.List;
 import java.util.Arrays;
 
 /**
@@ -25,44 +30,164 @@
  */
 public class ReportLogTest extends TestCase {
 
-    private static final double[] VALUES = new double[] {1, 11, 21, 1211, 111221};
+    private static final String SOURCE = "Source";
+    private static final String MESSAGE = "Message";
+    private static final double[] VALUES = new double[] {.1, 124, 4736, 835.683, 98, 395};
+    private static final String HEADER_XML =
+            "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>";
+    private static final String SUMMARY_XML =
+            HEADER_XML + "\r\n" +
+            "<Summary>\r\n" +
+            "  <Metric source=\"com.android.compatibility.common.util.ReportLogTest#%s\" message=\"Sample\" score_type=\"higher_better\" score_unit=\"byte\">\r\n" +
+            "    <Value>1.0</Value>\r\n" +
+            "  </Metric>\r\n" +
+            "</Summary>";
+    private static final String DETAIL_XML =
+            "<Detail>\r\n" +
+            "  <Metric source=\"com.android.compatibility.common.util.ReportLogTest#%s\" message=\"Details\" score_type=\"neutral\" score_unit=\"fps\">\r\n" +
+            "    <Value>0.1</Value>\r\n" +
+            "    <Value>124.0</Value>\r\n" +
+            "    <Value>4736.0</Value>\r\n" +
+            "    <Value>835.683</Value>\r\n" +
+            "    <Value>98.0</Value>\r\n" +
+            "    <Value>395.0</Value>\r\n" +
+            "  </Metric>\r\n" +
+            "</Detail>";
+    private static final String FULL_XML = SUMMARY_XML + "\r\n" + DETAIL_XML;
 
-    private static final String EXPECTED_ENCODED_REPORT_LOG =
-            "com.android.compatibility.common.util.ReportLogTest#testEncodeDecode:44|" +
-            "Sample Summary| |HIGHER_BETTER|BYTE|1.0 ++++" +
-            "com.android.compatibility.common.util.ReportLogTest#testEncodeDecode:45|" +
-            "Details| |NEUTRAL|FPS|1.0 11.0 21.0 1211.0 111221.0 ";
-    private ReportLog reportLog;
+    private ReportLog mReportLog;
 
     @Override
     protected void setUp() throws Exception {
-        this.reportLog = new ReportLog();
+        mReportLog = new ReportLog();
     }
 
-    public void testEncodeDecode() {
-
-        reportLog.setSummary("Sample Summary", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
-        reportLog.addValues("Details", VALUES, ResultType.NEUTRAL, ResultUnit.FPS);
-
-        String encodedReportLog = reportLog.toEncodedString();
-        assertEquals(EXPECTED_ENCODED_REPORT_LOG, encodedReportLog);
-
-        ReportLog decodedReportLog = ReportLog.fromEncodedString(encodedReportLog);
-        ReportLog.Result summary = reportLog.getSummary();
-        assertEquals("Sample Summary", summary.getMessage());
-        assertFalse(summary.getLocation().isEmpty());
-        assertEquals(ResultType.HIGHER_BETTER, summary.getType());
-        assertEquals(ResultUnit.BYTE, summary.getUnit());
-        assertTrue(Arrays.equals(new double[] {1.0}, summary.getValues()));
-
-        assertEquals(1, decodedReportLog.getDetailedMetrics().size());
-        ReportLog.Result detail = decodedReportLog.getDetailedMetrics().get(0);
-        assertEquals("Details", detail.getMessage());
-        assertFalse(detail.getLocation().isEmpty());
-        assertEquals(ResultType.NEUTRAL, detail.getType());
-        assertEquals(ResultUnit.FPS, detail.getUnit());
-        assertTrue(Arrays.equals(VALUES, detail.getValues()));
-
-        assertEquals(encodedReportLog, decodedReportLog.toEncodedString());
+    public void testSerialize_null() throws Exception {
+        try {
+            ReportLog.serialize(null);
+            fail("Expected IllegalArgumentException when serializing an empty report");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
     }
+
+    public void testSerialize_noData() throws Exception {
+        try {
+            ReportLog.serialize(mReportLog);
+            fail("Expected IllegalArgumentException when serializing an empty report");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+
+    public void testSerialize_summaryOnly() throws Exception {
+        mReportLog.setSummary("Sample", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
+        assertEquals(String.format(SUMMARY_XML, "testSerialize_summaryOnly:84"),
+                ReportLog.serialize(mReportLog));
+    }
+
+    public void testSerialize_detailOnly() throws Exception {
+        mReportLog.addValues("Details", VALUES, ResultType.NEUTRAL, ResultUnit.FPS);
+        try {
+            ReportLog.serialize(mReportLog);
+            fail("Expected IllegalArgumentException when serializing report without summary");
+        } catch(IllegalArgumentException e) {
+            // Expected
+        }
+    }
+
+    public void testSerialize_full() throws Exception {
+        mReportLog.setSummary("Sample", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
+        mReportLog.addValues("Details", VALUES, ResultType.NEUTRAL, ResultUnit.FPS);
+        assertEquals(String.format(FULL_XML, "testSerialize_full:100", "testSerialize_full:101"),
+                ReportLog.serialize(mReportLog));
+    }
+
+    public void testParse_null() throws Exception {
+        try {
+            ReportLog.parse((String) null);
+            fail("Expected IllegalArgumentException when passing a null report");
+        } catch(IllegalArgumentException e) {
+            // Expected
+        }
+    }
+
+    public void testParse_noData() throws Exception {
+        try {
+            ReportLog.parse(HEADER_XML);
+            fail("Expected XmlPullParserException when passing a report with no content");
+        } catch(XmlPullParserException e) {
+            // Expected
+        }
+    }
+
+    public void testParse_summaryOnly() throws Exception {
+        ReportLog report = ReportLog.parse(String.format(SUMMARY_XML, "testParse_summaryOnly:125"));
+        assertNotNull(report);
+        assertEquals("Sample", report.getSummary().getMessage());
+    }
+
+    public void testParse_detailOnly() throws Exception {
+        try {
+            ReportLog.parse(String.format(DETAIL_XML, "testParse_detailOnly:132"));
+            fail("Expected XmlPullParserException when serializing report without summary");
+        } catch (XmlPullParserException e) {
+            // Expected
+        }
+    }
+
+    public void testParse_full() throws Exception {
+        ReportLog report = ReportLog.parse(String.format(FULL_XML, "testParse_full:140",
+                "testParse_full:138"));
+        assertNotNull(report);
+        assertEquals("Sample", report.getSummary().getMessage());
+        List<Metric> details = report.getDetailedMetrics();
+        assertEquals(1, details.size());
+        assertEquals("Details", details.get(0).getMessage());
+    }
+
+    public void testLimits_source() throws Exception {
+        // Should pass with a short source.
+        Metric metric = new Metric(SOURCE, MESSAGE, 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
+        assertEquals("Expected message to be ok", SOURCE, metric.getSource());
+        // Make a long source.
+        StringBuilder sb = new StringBuilder();
+        // 40 x "Source" = 240 character string
+        for (int i = 0; i < 40; i++) sb.append(SOURCE);
+        String source = sb.toString();
+        // Should be trimmed because source is too long.
+        metric = new Metric(source, MESSAGE, 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
+        assertEquals("Expected source to be trimmed", source.substring(source.length() - 200),
+                metric.getSource());
+    }
+
+    public void testLimits_message() throws Exception {
+        // Should pass with a short message.
+        Metric metric = new Metric(SOURCE, MESSAGE, 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
+        assertEquals("Expected message to be ok", MESSAGE, metric.getMessage());
+        // Make a long message.
+        StringBuilder sb = new StringBuilder();
+        // 40 x "Message" = 280 character string
+        for (int i = 0; i < 40; i++) sb.append(MESSAGE);
+        String message = sb.toString();
+        // Should be trimmed because message is too long.
+        metric = new Metric(SOURCE, message, 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
+        assertEquals("Expected message to be trimmed", message.substring(0, 200),
+                metric.getMessage());
+    }
+
+    public void testLimits_values() throws Exception {
+        // Should pass with a small array.
+        Metric metric = new Metric(SOURCE, MESSAGE, VALUES, ResultType.HIGHER_BETTER,
+                ResultUnit.BYTE);
+        assertTrue("Expected values to be ok", Arrays.equals(VALUES, metric.getValues()));
+        // Make a big array.
+        double[] values = new double[1001];
+        for (int i = 0; i < values.length; i++) values[i] = i;
+        // Should be trimmed because array is too big.
+        metric = new Metric(SOURCE, MESSAGE, values, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
+        assertTrue("Expected values to be trimmed", Arrays.equals(Arrays.copyOf(values, 1000),
+                metric.getValues()));
+    }
+
 }
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
new file mode 100644
index 0000000..be3c109
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.compatibility.common.util;
+
+import com.android.tradefed.util.FileUtil;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link ResultHandler}
+ */
+public class ResultHandlerTest extends TestCase {
+
+    private static final String SUITE_NAME = "CTS";
+    private static final String SUITE_VERSION = "5.0";
+    private static final String SUITE_PLAN = "cts";
+    private static final String REPORT_VERSION = "5.0";
+    private static final String OS_NAME = System.getProperty("os.name");
+    private static final String OS_VERSION = System.getProperty("os.version");
+    private static final String OS_ARCH = System.getProperty("os.arch");
+    private static final String JAVA_VENDOR = System.getProperty("java.vendor");
+    private static final String JAVA_VERSION = System.getProperty("java.version");
+    private static final String NAME_A = "ModuleA";
+    private static final String NAME_B = "ModuleB";
+    private static final String ABI = "mips64";
+    private static final String ID_A = AbiUtils.createId(ABI, NAME_A);
+    private static final String ID_B = AbiUtils.createId(ABI, NAME_B);
+    private static final String DEVICE_A = "device123";
+    private static final String DEVICE_B = "device456";
+    private static final String DEVICES = "device456,device123";
+    private static final String CLASS_A = "android.test.Foor";
+    private static final String CLASS_B = "android.test.Bar";
+    private static final String METHOD_1 = "testBlah1";
+    private static final String METHOD_2 = "testBlah2";
+    private static final String METHOD_3 = "testBlah3";
+    private static final String METHOD_4 = "testBlah4";
+    private static final String SUMMARY_SOURCE = String.format("%s#%s:20", CLASS_B, METHOD_4);
+    private static final String DETAILS_SOURCE = String.format("%s#%s:18", CLASS_B, METHOD_4);
+    private static final String SUMMARY_MESSAGE = "Headline";
+    private static final double SUMMARY_VALUE = 9001;
+    private static final String DETAILS_MESSAGE = "Deats";
+    private static final double DETAILS_VALUE_1 = 14;
+    private static final double DETAILS_VALUE_2 = 18;
+    private static final double DETAILS_VALUE_3 = 17;
+    private static final String MESSAGE = "Something small is not alright";
+    private static final String STACK_TRACE = "Something small is not alright\n " +
+            "at four.big.insects.Marley.sing(Marley.java:10)";
+    private static final long START_MS = 1431586801000L;
+    private static final long END_MS = 1431673199000L;
+    private static final String REFERENCE_URL="http://android.com";
+    private static final String JOIN = "%s%s";
+    private static final String XML_BASE =
+            "<?xml version='1.0' encoding='UTF-8' standalone='no' ?>" +
+            "<?xml-stylesheet type=\"text/xsl\" href=\"compatibility_result.xsl\"?>\n" +
+            "<Result start=\"%d\" end=\"%d\" suite_name=\"%s\" suite_version=\"%s\" " +
+            "suite_plan=\"%s\" report_version=\"%s\" devices=\"%s\" host_name=\"%s\"" +
+            "os_name=\"%s\" os_version=\"%s\" os_arch=\"%s\" java_vendor=\"%s\"" +
+            "java_version=\"%s\" reference_url=\"%s\">\n" +
+            "%s%s%s" +
+            "</Result>";
+    private static final String XML_DEVICE_INFO =
+            "  <Build build_fingerprint=\"%s\" />\n";
+    private static final String XML_SUMMARY =
+            "  <Summary pass=\"%d\" failed=\"%d\" not_executed=\"%d\" />\n";
+    private static final String XML_MODULE =
+            "  <Module name=\"%s\" abi=\"%s\" device=\"%s\">\n" +
+            "%s" +
+            "  </Module>\n";
+    private static final String XML_CASE =
+            "    <TestCase name=\"%s\">\n" +
+            "%s" +
+            "    </TestCase>\n";
+    private static final String XML_TEST_PASS =
+            "      <Test result=\"pass\" name=\"%s\"/>\n";
+    private static final String XML_TEST_NOT_EXECUTED =
+            "      <Test result=\"not_executed\" name=\"%s\"/>\n";
+    private static final String XML_TEST_FAIL =
+            "      <Test result=\"fail\" name=\"%s\">\n" +
+            "        <Failure message=\"%s\">\n" +
+            "          <StackTrace>%s</StackTrace>\n" +
+            "        </Failure>\n" +
+            "      </Test>\n";
+    private static final String XML_TEST_RESULT =
+            "      <Test result=\"pass\" name=\"%s\">\n" +
+            "        <Summary>\n" +
+            "          <Metric source=\"%s\" message=\"%s\" score_type=\"%s\" score_unit=\"%s\">\n" +
+            "             <Value>%s</Value>\n" +
+            "          </Metric>\n" +
+            "        </Summary>\n" +
+            "        <Detail>\n" +
+            "          <Metric source=\"%s\" message=\"%s\" score_type=\"%s\" score_unit=\"%s\">\n" +
+            "            <Value>%s</Value>\n" +
+            "            <Value>%s</Value>\n" +
+            "            <Value>%s</Value>\n" +
+            "          </Metric>\n" +
+            "        </Detail>\n" +
+            "      </Test>\n";
+    private File resultsDir = null;
+    private File resultDir = null;
+
+    @Override
+    public void setUp() throws Exception {
+        resultsDir = FileUtil.createTempDir("results");
+        resultDir = FileUtil.createTempDir("12345", resultsDir);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (resultsDir != null) {
+            FileUtil.recursiveDelete(resultsDir);
+        }
+    }
+
+    public void testSerialization() throws Exception {
+        IInvocationResult result = new InvocationResult(resultDir);
+        result.setStartTime(START_MS);
+        result.setTestPlan(SUITE_PLAN);
+        result.addDeviceSerial(DEVICE_A);
+        result.addDeviceSerial(DEVICE_B);
+        IModuleResult moduleA = result.getOrCreateModule(ID_A);
+        ICaseResult moduleACase = moduleA.getOrCreateResult(CLASS_A);
+        ITestResult moduleATest1 = moduleACase.getOrCreateResult(METHOD_1);
+        moduleATest1.setResultStatus(TestStatus.PASS);
+        ITestResult moduleATest2 = moduleACase.getOrCreateResult(METHOD_2);
+        moduleATest2.setResultStatus(TestStatus.NOT_EXECUTED);
+
+        IModuleResult moduleB = result.getOrCreateModule(ID_B);
+        ICaseResult moduleBCase = moduleB.getOrCreateResult(CLASS_B);
+        ITestResult moduleBTest3 = moduleBCase.getOrCreateResult(METHOD_3);
+        moduleBTest3.setResultStatus(TestStatus.FAIL);
+        moduleBTest3.setMessage(MESSAGE);
+        moduleBTest3.setStackTrace(STACK_TRACE);
+        ITestResult moduleBTest4 = moduleBCase.getOrCreateResult(METHOD_4);
+        moduleBTest4.setResultStatus(TestStatus.PASS);
+        ReportLog report = new ReportLog();
+        ReportLog.Metric summary = new ReportLog.Metric(SUMMARY_SOURCE, SUMMARY_MESSAGE,
+                SUMMARY_VALUE, ResultType.HIGHER_BETTER, ResultUnit.SCORE);
+        report.setSummary(summary);
+        ReportLog.Metric details = new ReportLog.Metric(DETAILS_SOURCE, DETAILS_MESSAGE,
+                new double[] {DETAILS_VALUE_1, DETAILS_VALUE_2, DETAILS_VALUE_3},
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.addMetric(details);
+        moduleBTest4.setReportLog(report);
+
+        // Serialize to file
+        ResultHandler.writeResults(SUITE_NAME, SUITE_VERSION, SUITE_PLAN, result, resultDir,
+                START_MS, END_MS, REFERENCE_URL);
+
+        // Parse the results and assert correctness
+        checkResult(ResultHandler.getResults(resultsDir), resultDir);
+    }
+
+    public void testParsing() throws Exception {
+        File resultsDir = null;
+        FileWriter writer = null;
+        try {
+            resultsDir = FileUtil.createTempDir("results");
+            File resultDir = FileUtil.createTempDir("12345", resultsDir);
+            // Create the result file
+            File resultFile = new File(resultDir, ResultHandler.TEST_RESULT_FILE_NAME);
+            writer = new FileWriter(resultFile);
+            String deviceInfo = String.format(XML_DEVICE_INFO, DEVICE_A);
+            String summary = String.format(XML_SUMMARY, 2, 1, 1);
+            String moduleATest1 = String.format(XML_TEST_PASS, METHOD_1);
+            String moduleATest2 = String.format(XML_TEST_NOT_EXECUTED, METHOD_2);
+            String moduleATests = String.format(JOIN, moduleATest1, moduleATest2);
+            String moduleACases = String.format(XML_CASE, CLASS_A, moduleATests);
+            String moduleA = String.format(XML_MODULE, NAME_A, ABI, DEVICE_A, moduleACases);
+            String moduleBTest3 = String.format(XML_TEST_FAIL, METHOD_3, MESSAGE, STACK_TRACE);
+            String moduleBTest4 = String.format(XML_TEST_RESULT, METHOD_4,
+                    SUMMARY_SOURCE, SUMMARY_MESSAGE, ResultType.HIGHER_BETTER.toReportString(),
+                    ResultUnit.SCORE.toReportString(), Double.toString(SUMMARY_VALUE),
+                    DETAILS_SOURCE, DETAILS_MESSAGE, ResultType.LOWER_BETTER.toReportString(),
+                    ResultUnit.MS.toReportString(), Double.toString(DETAILS_VALUE_1),
+                    Double.toString(DETAILS_VALUE_2), Double.toString(DETAILS_VALUE_3));
+            String moduleBTests = String.format(JOIN, moduleBTest3, moduleBTest4);
+            String moduleBCases = String.format(XML_CASE, CLASS_B, moduleBTests);
+            String moduleB = String.format(XML_MODULE, NAME_B, ABI, DEVICE_B, moduleBCases);
+            String modules = String.format(JOIN, moduleA, moduleB);
+            String hostName = "";
+            try {
+                hostName = InetAddress.getLocalHost().getHostName();
+            } catch (UnknownHostException ignored) {}
+            String output = String.format(XML_BASE, START_MS, END_MS, SUITE_NAME, SUITE_VERSION,
+                    SUITE_PLAN, REPORT_VERSION, DEVICES, hostName, OS_NAME, OS_VERSION, OS_ARCH,
+                    JAVA_VENDOR, JAVA_VERSION, REFERENCE_URL, deviceInfo, summary, modules);
+            writer.write(output);
+            writer.flush();
+
+            // Parse the results and assert correctness
+            checkResult(ResultHandler.getResults(resultsDir), resultDir);
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
+
+    private void checkResult(List<IInvocationResult> results, File resultDir) throws Exception {
+        assertEquals("Expected 1 result", 1, results.size());
+        IInvocationResult result = results.get(0);
+        assertEquals("Expected 2 passes", 2, result.countResults(TestStatus.PASS));
+        assertEquals("Expected 1 failure", 1, result.countResults(TestStatus.FAIL));
+        assertEquals("Expected 1 not executed", 1, result.countResults(TestStatus.NOT_EXECUTED));
+        Set<String> serials = result.getDeviceSerials();
+        assertTrue("Missing device", serials.contains(DEVICE_A));
+        assertTrue("Missing device", serials.contains(DEVICE_B));
+        assertEquals("Expected 2 devices", 2, serials.size());
+        assertTrue("Incorrect devices", serials.contains(DEVICE_A) && serials.contains(DEVICE_B));
+        assertEquals("Incorrect result dir", resultDir.getAbsolutePath(),
+                result.getResultDir().getAbsolutePath());
+        assertEquals("Incorrect start time", START_MS, result.getStartTime());
+        assertEquals("Incorrect test plan", SUITE_PLAN, result.getTestPlan());
+
+        List<IModuleResult> modules = result.getModules();
+        assertEquals("Expected 2 modules", 2, modules.size());
+
+        IModuleResult moduleA = modules.get(0);
+        assertEquals("Expected 1 pass", 1, moduleA.countResults(TestStatus.PASS));
+        assertEquals("Expected 0 failures", 0, moduleA.countResults(TestStatus.FAIL));
+        assertEquals("Expected 1 not executed", 1, moduleA.countResults(TestStatus.NOT_EXECUTED));
+        assertEquals("Incorrect ABI", ABI, moduleA.getAbi());
+        assertEquals("Incorrect name", NAME_A, moduleA.getName());
+        assertEquals("Incorrect ID", ID_A, moduleA.getId());
+        List<ICaseResult> moduleACases = moduleA.getResults();
+        assertEquals("Expected 1 test case", 1, moduleACases.size());
+        ICaseResult moduleACase = moduleACases.get(0);
+        assertEquals("Incorrect name", CLASS_A, moduleACase.getName());
+        List<ITestResult> moduleAResults = moduleACase.getResults();
+        assertEquals("Expected 2 results", 2, moduleAResults.size());
+        ITestResult moduleATest1 = moduleAResults.get(0);
+        assertEquals("Incorrect name", METHOD_1, moduleATest1.getName());
+        assertEquals("Incorrect result", TestStatus.PASS, moduleATest1.getResultStatus());
+        assertNull("Unexpected bugreport", moduleATest1.getBugReport());
+        assertNull("Unexpected log", moduleATest1.getLog());
+        assertNull("Unexpected screenshot", moduleATest1.getScreenshot());
+        assertNull("Unexpected message", moduleATest1.getMessage());
+        assertNull("Unexpected stack trace", moduleATest1.getStackTrace());
+        assertNull("Unexpected report", moduleATest1.getReportLog());
+        ITestResult moduleATest2 = moduleAResults.get(1);
+        assertEquals("Incorrect name", METHOD_2, moduleATest2.getName());
+        assertEquals("Incorrect result", TestStatus.NOT_EXECUTED, moduleATest2.getResultStatus());
+        assertNull("Unexpected bugreport", moduleATest2.getBugReport());
+        assertNull("Unexpected log", moduleATest2.getLog());
+        assertNull("Unexpected screenshot", moduleATest2.getScreenshot());
+        assertNull("Unexpected message", moduleATest2.getMessage());
+        assertNull("Unexpected stack trace", moduleATest2.getStackTrace());
+        assertNull("Unexpected report", moduleATest2.getReportLog());
+
+        IModuleResult moduleB = modules.get(1);
+        assertEquals("Expected 1 pass", 1, moduleB.countResults(TestStatus.PASS));
+        assertEquals("Expected 1 failure", 1, moduleB.countResults(TestStatus.FAIL));
+        assertEquals("Expected 0 not executed", 0, moduleB.countResults(TestStatus.NOT_EXECUTED));
+        assertEquals("Incorrect ABI", ABI, moduleB.getAbi());
+        assertEquals("Incorrect name", NAME_B, moduleB.getName());
+        assertEquals("Incorrect ID", ID_B, moduleB.getId());
+        List<ICaseResult> moduleBCases = moduleB.getResults();
+        assertEquals("Expected 1 test case", 1, moduleBCases.size());
+        ICaseResult moduleBCase = moduleBCases.get(0);
+        assertEquals("Incorrect name", CLASS_B, moduleBCase.getName());
+        List<ITestResult> moduleBResults = moduleBCase.getResults();
+        assertEquals("Expected 2 results", 2, moduleBResults.size());
+        ITestResult moduleBTest3 = moduleBResults.get(0);
+        assertEquals("Incorrect name", METHOD_3, moduleBTest3.getName());
+        assertEquals("Incorrect result", TestStatus.FAIL, moduleBTest3.getResultStatus());
+        assertNull("Unexpected bugreport", moduleBTest3.getBugReport());
+        assertNull("Unexpected log", moduleBTest3.getLog());
+        assertNull("Unexpected screenshot", moduleBTest3.getScreenshot());
+        assertEquals("Incorrect message", MESSAGE, moduleBTest3.getMessage());
+        assertEquals("Incorrect stack trace", STACK_TRACE, moduleBTest3.getStackTrace());
+        assertNull("Unexpected report", moduleBTest3.getReportLog());
+        ITestResult moduleBTest4 = moduleBResults.get(1);
+        assertEquals("Incorrect name", METHOD_4, moduleBTest4.getName());
+        assertEquals("Incorrect result", TestStatus.PASS, moduleBTest4.getResultStatus());
+        assertNull("Unexpected bugreport", moduleBTest4.getBugReport());
+        assertNull("Unexpected log", moduleBTest4.getLog());
+        assertNull("Unexpected screenshot", moduleBTest4.getScreenshot());
+        assertNull("Unexpected message", moduleBTest4.getMessage());
+        assertNull("Unexpected stack trace", moduleBTest4.getStackTrace());
+        ReportLog report = moduleBTest4.getReportLog();
+        assertNotNull("Expected report", report);
+        ReportLog.Metric summary = report.getSummary();
+        assertNotNull("Expected report summary", summary);
+        assertEquals("Incorrect source", SUMMARY_SOURCE, summary.getSource());
+        assertEquals("Incorrect message", SUMMARY_MESSAGE, summary.getMessage());
+        assertEquals("Incorrect type", ResultType.HIGHER_BETTER, summary.getType());
+        assertEquals("Incorrect unit", ResultUnit.SCORE, summary.getUnit());
+        assertTrue("Incorrect values", Arrays.equals(new double[] { SUMMARY_VALUE },
+                summary.getValues()));
+        List<ReportLog.Metric> details = report.getDetailedMetrics();
+        assertEquals("Expected 1 report detail", 1, details.size());
+        ReportLog.Metric detail = details.get(0);
+        assertEquals("Incorrect source", DETAILS_SOURCE, detail.getSource());
+        assertEquals("Incorrect message", DETAILS_MESSAGE, detail.getMessage());
+        assertEquals("Incorrect type", ResultType.LOWER_BETTER, detail.getType());
+        assertEquals("Incorrect unit", ResultUnit.MS, detail.getUnit());
+        assertTrue("Incorrect values", Arrays.equals(new double[] { DETAILS_VALUE_1,
+                DETAILS_VALUE_2, DETAILS_VALUE_3 }, detail.getValues()));
+    }
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/StatTest.java b/common/util/tests/src/com/android/compatibility/common/util/StatTest.java
new file mode 100644
index 0000000..6e53d48
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/StatTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.compatibility.common.util;
+
+import com.android.compatibility.common.util.Stat;
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for the {@link Stat} class.
+ */
+public class StatTest extends TestCase {
+
+    /**
+     * Test {@link Stat#get95PercentileValue(double[])}.
+     */
+    public void testGet95PercentileValue() {
+        double[] values = new double[100];
+        for (int i = 0; i < 100; i++) {
+            values[i] = i;
+        }
+        assertEquals(95, (int) Stat.get95PercentileValue(values));
+
+        values = new double[1000];
+        for (int i = 0; i < 1000; i++) {
+            values[i] = i;
+        }
+        assertEquals(950, (int) Stat.get95PercentileValue(values));
+
+        values = new double[100];
+        for (int i = 0; i < 100; i++) {
+            values[i] = i * i;
+        }
+        assertEquals(95 * 95, (int) Stat.get95PercentileValue(values));
+    }
+
+    /**
+     * Test {@link Stat#getAverage(double[])}.
+     */
+    public void testGetAverage() {
+        double[] values = new double[]{0, 1, 2, 3, 4};
+        double average = Stat.getAverage(values);
+        assertEquals(2.0, average, 0.00001);
+
+        values = new double[]{1, 2, 3, 4, 5};
+        average = Stat.getAverage(values);
+        assertEquals(3.0, average, 0.00001);
+
+        values = new double[]{0, 1, 4, 9, 16};
+        average = Stat.getAverage(values);
+        assertEquals(6.0, average, 0.00001);
+    }
+
+    /**
+     * Test standard deviation.
+     */
+    public void testGetStandardDeviation() {
+        double[] values = new double[]{0, 1, 2, 3, 4};
+        double stddev = Stat.getStat(values).mStddev;
+        assertEquals(Math.sqrt(2.5), stddev, 0.00001);
+
+        values = new double[]{1, 2, 3, 4, 5};
+        stddev = Stat.getStat(values).mStddev;
+        assertEquals(Math.sqrt(2.5), stddev, 0.00001);
+
+        values = new double[]{0, 2, 4, 6, 8};
+        stddev = Stat.getStat(values).mStddev;
+        assertEquals(Math.sqrt(10.0), stddev, 0.00001);
+    }
+
+
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/TestFilterTest.java b/common/util/tests/src/com/android/compatibility/common/util/TestFilterTest.java
new file mode 100644
index 0000000..bc1091bb
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/TestFilterTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.compatibility.common.util;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link TestFilter}
+ */
+public class TestFilterTest extends TestCase {
+
+    private static final String NAME = "ModuleName";
+    private static final String ABI = "mips64";
+    private static final String TEST = "com.android.foobar.Blah#testAllTheThings";
+    private static final String NAME_FILTER = String.format("%s", NAME);
+    private static final String ABI_NAME_FILTER = String.format("%s %s", ABI, NAME);
+    private static final String NAME_TEST_FILTER = String.format("%s %s", NAME, TEST);
+    private static final String FULL_FILTER = String.format("%s %s %s", ABI, NAME, TEST);
+
+    public void testParseNameFilter() {
+        TestFilter filter = TestFilter.createFrom(NAME_FILTER);
+        assertNull("Incorrect abi", filter.getAbi());
+        assertEquals("Incorrect name", NAME, filter.getName());
+        assertNull("Incorrect test", filter.getTest());
+    }
+
+    public void testParseAbiNameFilter() {
+        TestFilter filter = TestFilter.createFrom(ABI_NAME_FILTER);
+        assertEquals("Incorrect abi", ABI, filter.getAbi());
+        assertEquals("Incorrect name", NAME, filter.getName());
+        assertNull("Incorrect test", filter.getTest());
+    }
+
+    public void testParseNameTestFilter() {
+        TestFilter filter = TestFilter.createFrom(NAME_TEST_FILTER);
+        assertNull("Incorrect abi", filter.getAbi());
+        assertEquals("Incorrect name", NAME, filter.getName());
+        assertEquals("Incorrect test", TEST, filter.getTest());
+    }
+
+    public void testParseFullFilter() {
+        TestFilter filter = TestFilter.createFrom(FULL_FILTER);
+        assertEquals("Incorrect abi", ABI, filter.getAbi());
+        assertEquals("Incorrect name", NAME, filter.getName());
+        assertEquals("Incorrect test", TEST, filter.getTest());
+    }
+
+    public void testCreateNameFilter() {
+        TestFilter filter = new TestFilter(null, NAME, null);
+        assertEquals("Incorrect filter", NAME_FILTER, filter.toString());
+    }
+
+    public void testCreateAbiNameFilter() {
+        TestFilter filter = new TestFilter(ABI, NAME, null);
+        assertEquals("Incorrect filter", ABI_NAME_FILTER, filter.toString());
+    }
+
+    public void testCreateNameTestFilter() {
+        TestFilter filter = new TestFilter(null, NAME, TEST);
+        assertEquals("Incorrect filter", NAME_TEST_FILTER, filter.toString());
+    }
+
+    public void testCreateFullFilter() {
+        TestFilter filter = new TestFilter(ABI, NAME, TEST);
+        assertEquals("Incorrect filter", FULL_FILTER, filter.toString());
+    }
+
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/TestResultTest.java b/common/util/tests/src/com/android/compatibility/common/util/TestResultTest.java
new file mode 100644
index 0000000..5e4431e
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/TestResultTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link TestResult}
+ */
+public class TestResultTest extends TestCase {
+
+    private static final String CLASS = "android.test.FoorBar";
+    private static final String METHOD_1 = "testBlah1";
+    private static final String TEST_1 = String.format("%s#%s", CLASS, METHOD_1);
+    private CaseResult mCase;
+    private TestResult mResult;
+
+    @Override
+    public void setUp() throws Exception {
+        mCase = new CaseResult(CLASS);
+        mResult = new TestResult(mCase, METHOD_1);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mResult = null;
+    }
+
+    public void testAccessors() throws Exception {
+        assertEquals("Incorrect test name", METHOD_1, mResult.getName());
+        assertEquals("Incorrect full name", TEST_1, mResult.getFullName());
+    }
+
+}
\ No newline at end of file
diff --git a/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java b/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
index 348c680..967b8a8 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -11,23 +11,36 @@
  * 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
+ * limitations under the License.
  */
-
 package com.android.compatibility.common.util;
 
+import junit.framework.Test;
 import junit.framework.TestSuite;
 
 /**
- * A {@link TestSuite} for the common.util package.
+ * A test suite for all util unit tests.
+ * <p/>
+ * All tests listed here should be self-contained, and do not require any external dependencies.
  */
 public class UnitTests extends TestSuite {
 
     public UnitTests() {
         super();
-
-        addTestSuite(MetricsStoreTest.class);
+        addTestSuite(AbiUtilsTest.class);
+        addTestSuite(CaseResultTest.class);
+        addTestSuite(DynamicConfigTest.class);
         addTestSuite(MetricsXmlSerializerTest.class);
+        addTestSuite(ModuleResultTest.class);
+        addTestSuite(MultipartFormTest.class);
         addTestSuite(ReportLogTest.class);
+        addTestSuite(StatTest.class);
+        addTestSuite(TestFilterTest.class);
+        addTestSuite(TestResultTest.class);
+        addTestSuite(ResultHandlerTest.class);
     }
-}
+
+    public static Test suite() {
+        return new UnitTests();
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/aadb/Android.mk b/hostsidetests/aadb/Android.mk
index b9551d1..c7651ba 100644
--- a/hostsidetests/aadb/Android.mk
+++ b/hostsidetests/aadb/Android.mk
@@ -19,12 +19,16 @@
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_MODULE := CtsAdbTests
+# Adb test cases, but name 'aadb' ensures adb tests run before all other modules depending on adb
+LOCAL_MODULE := CtsAadbHostTestCases
 
 LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
 
 LOCAL_CTS_TEST_PACKAGE := android.aadb
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 # Build the test APKs using their own makefiles
diff --git a/hostsidetests/aadb/AndroidTest.xml b/hostsidetests/aadb/AndroidTest.xml
new file mode 100644
index 0000000..cfba81e
--- /dev/null
+++ b/hostsidetests/aadb/AndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for the CTS aadb host tests">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest">
+        <option name="jar" value="CtsAadbHostTestCases.jar" />
+        <option name="runtime-hint" value="5m30s" />
+    </test>
+</configuration>
diff --git a/hostsidetests/aadb/src/android/aadb/cts/TestDeviceFuncTest.java b/hostsidetests/aadb/src/android/aadb/cts/TestDeviceFuncTest.java
new file mode 100644
index 0000000..ddc3e82
--- /dev/null
+++ b/hostsidetests/aadb/src/android/aadb/cts/TestDeviceFuncTest.java
@@ -0,0 +1,404 @@
+/*
+ * 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 android.aadb.cts;
+
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.IFileEntry;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.InputStreamSource;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.RunUtil;
+import com.android.tradefed.util.StreamUtil;
+
+import java.awt.image.BufferedImage;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.TimeZone;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Functional tests for adb connection
+ * <p/>
+ * Requires a physical device to be connected.
+ */
+public class TestDeviceFuncTest extends DeviceTestCase {
+
+    private static final String LOG_TAG = "TestDeviceFuncTest";
+    private ITestDevice mTestDevice;
+    /** Expect bugreports to be at least a meg. */
+    private static final int mMinBugreportBytes = 1024 * 1024;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTestDevice = getDevice();
+    }
+
+    /**
+     * Simple testcase to ensure that the grabbing a bugreport from a real TestDevice works.
+     */
+    public void testBugreport() throws Exception {
+        String data = StreamUtil.getStringFromStream(
+                mTestDevice.getBugreport().createInputStream());
+        assertTrue(String.format("Expected at least %d characters; only saw %d", mMinBugreportBytes,
+                data.length()), data.length() >= mMinBugreportBytes);
+        // TODO: check the captured report more extensively, perhaps using loganalysis
+    }
+
+    /**
+     * Simple normal case test for
+     * {@link TestDevice#executeShellCommand(String)}.
+     * <p/>
+     * Do a 'shell ls' command, and verify /data and /system are listed in result.
+     */
+    public void testExecuteShellCommand() throws IOException, DeviceNotAvailableException {
+        Log.i(LOG_TAG, "testExecuteShellCommand");
+        assertSimpleShellCommand();
+    }
+
+    /**
+     * Verify that a simple {@link TestDevice#executeShellCommand(String)} command is successful.
+     */
+    private void assertSimpleShellCommand() throws DeviceNotAvailableException {
+    	// Check for expected contents of device's root directory
+        final String output = mTestDevice.executeShellCommand("ls /");
+        assertTrue(output.contains("data"));
+        assertTrue(output.contains("system"));
+    }
+
+
+    /**
+     * Push and then pull a file from device, and verify contents are as expected.
+     */
+    public void testPushPull_normal() throws IOException, DeviceNotAvailableException {
+        Log.i(LOG_TAG, "testPushPull");
+        File tmpFile = null;
+        File tmpDestFile = null;
+        String deviceFilePath = null;
+
+        try {
+            tmpFile = createTempTestFile(null);
+            String externalStorePath = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
+            assertNotNull(externalStorePath);
+            deviceFilePath = String.format("%s/%s", externalStorePath, "tmp_testPushPull.txt");
+            // ensure file does not already exist
+            mTestDevice.executeShellCommand(String.format("rm %s", deviceFilePath));
+            assertFalse(String.format("%s exists", deviceFilePath),
+                    mTestDevice.doesFileExist(deviceFilePath));
+
+            assertTrue(mTestDevice.pushFile(tmpFile, deviceFilePath));
+            assertTrue(mTestDevice.doesFileExist(deviceFilePath));
+            tmpDestFile = FileUtil.createTempFile("tmp", "txt");
+            assertTrue(mTestDevice.pullFile(deviceFilePath, tmpDestFile));
+            assertTrue(compareFiles(tmpFile, tmpDestFile));
+        } finally {
+            if (tmpDestFile != null) {
+                tmpDestFile.delete();
+            }
+            if (deviceFilePath != null) {
+                mTestDevice.executeShellCommand(String.format("rm %s", deviceFilePath));
+            }
+        }
+    }
+
+    /**
+     * Push and then pull a file from device, and verify contents are as expected.
+     * <p />
+     * This variant of the test uses "${EXTERNAL_STORAGE}" in the pathname.
+     */
+    public void testPushPull_extStorageVariable() throws IOException, DeviceNotAvailableException {
+        Log.i(LOG_TAG, "testPushPull");
+        File tmpFile = null;
+        File tmpDestFile = null;
+        File tmpDestFile2 = null;
+        String deviceFilePath = null;
+        final String filename = "tmp_testPushPull.txt";
+
+        try {
+            tmpFile = createTempTestFile(null);
+            String externalStorePath = "${EXTERNAL_STORAGE}";
+            assertNotNull(externalStorePath);
+            deviceFilePath = String.format("%s/%s", externalStorePath, filename);
+            // ensure file does not already exist
+            mTestDevice.executeShellCommand(String.format("rm %s", deviceFilePath));
+            assertFalse(String.format("%s exists", deviceFilePath),
+                    mTestDevice.doesFileExist(deviceFilePath));
+
+            assertTrue(mTestDevice.pushFile(tmpFile, deviceFilePath));
+            assertTrue(mTestDevice.doesFileExist(deviceFilePath));
+            tmpDestFile = FileUtil.createTempFile("tmp", "txt");
+            assertTrue(mTestDevice.pullFile(deviceFilePath, tmpDestFile));
+            assertTrue(compareFiles(tmpFile, tmpDestFile));
+
+            tmpDestFile2 = mTestDevice.pullFileFromExternal(filename);
+            assertNotNull(tmpDestFile2);
+            assertTrue(compareFiles(tmpFile, tmpDestFile2));
+        } finally {
+            if (tmpDestFile != null) {
+                tmpDestFile.delete();
+            }
+            if (tmpDestFile2 != null) {
+                tmpDestFile2.delete();
+            }
+            if (deviceFilePath != null) {
+                mTestDevice.executeShellCommand(String.format("rm %s", deviceFilePath));
+            }
+        }
+    }
+
+    /**
+     * Test pulling a file from device that does not exist.
+     * <p/>
+     * Expect {@link TestDevice#pullFile(String)} to return <code>false</code>
+     */
+    public void testPull_noexist() throws IOException, DeviceNotAvailableException {
+        Log.i(LOG_TAG, "testPull_noexist");
+
+        // make sure the root path is valid
+        String externalStorePath =  mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
+        assertNotNull(externalStorePath);
+        String deviceFilePath = String.format("%s/%s", externalStorePath, "thisfiledoesntexist");
+        assertFalse(String.format("%s exists", deviceFilePath),
+                mTestDevice.doesFileExist(deviceFilePath));
+        assertNull(mTestDevice.pullFile(deviceFilePath));
+    }
+
+    private File createTempTestFile(File dir) throws IOException {
+        File tmpFile = null;
+        try {
+            final String fileContents = "this is the test file contents";
+            tmpFile = FileUtil.createTempFile("tmp", ".txt", dir);
+            FileUtil.writeToFile(fileContents, tmpFile);
+            return tmpFile;
+        } catch (IOException e) {
+            if (tmpFile != null) {
+                tmpFile.delete();
+            }
+            throw e;
+        }
+    }
+
+    /**
+     * Utility method to do byte-wise content comparison of two files.
+     */
+    private boolean compareFiles(File file1, File file2) throws IOException {
+        BufferedInputStream stream1 = null;
+        BufferedInputStream stream2 = null;
+
+        try {
+            stream1 = new BufferedInputStream(new FileInputStream(file1));
+            stream2 = new BufferedInputStream(new FileInputStream(file2));
+            boolean eof = false;
+            while (!eof) {
+                int byte1 = stream1.read();
+                int byte2 = stream2.read();
+                if (byte1 != byte2) {
+                    return false;
+                }
+                eof = byte1 == -1;
+            }
+            return true;
+        } finally {
+            if (stream1 != null) {
+                stream1.close();
+            }
+            if (stream2 != null) {
+                stream2.close();
+            }
+        }
+    }
+
+    /**
+     * Test syncing a single file using {@link TestDevice#syncFiles(File, String)}.
+     */
+    public void testSyncFiles_normal() throws Exception {
+        doTestSyncFiles(mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE));
+    }
+
+    /**
+     * Test syncing a single file using {@link TestDevice#syncFiles(File, String)}.
+     * <p />
+     * This variant of the test uses "${EXTERNAL_STORAGE}" in the pathname.
+     */
+    public void testSyncFiles_extStorageVariable() throws Exception {
+        doTestSyncFiles("${EXTERNAL_STORAGE}");
+    }
+
+    /**
+     * Test syncing a single file using {@link TestDevice#syncFiles(File, String)}.
+     */
+    public void doTestSyncFiles(String externalStorePath) throws Exception {
+        String expectedDeviceFilePath = null;
+
+        // create temp dir with one temp file
+        File tmpDir = FileUtil.createTempDir("tmp");
+        try {
+            File tmpFile = createTempTestFile(tmpDir);
+            // set last modified to 10 minutes ago
+            tmpFile.setLastModified(System.currentTimeMillis() - 10*60*1000);
+            assertNotNull(externalStorePath);
+            expectedDeviceFilePath = String.format("%s/%s/%s", externalStorePath,
+                    tmpDir.getName(), tmpFile.getName());
+
+            assertTrue(mTestDevice.syncFiles(tmpDir, externalStorePath));
+            assertTrue(mTestDevice.doesFileExist(expectedDeviceFilePath));
+
+            // get 'ls -l' attributes of file which includes timestamp
+            String origTmpFileStamp = mTestDevice.executeShellCommand(String.format("ls -l %s",
+                    expectedDeviceFilePath));
+            // now create another file and verify that is synced
+            File tmpFile2 = createTempTestFile(tmpDir);
+            tmpFile2.setLastModified(System.currentTimeMillis() - 10*60*1000);
+            assertTrue(mTestDevice.syncFiles(tmpDir, externalStorePath));
+            String expectedDeviceFilePath2 = String.format("%s/%s/%s", externalStorePath,
+                    tmpDir.getName(), tmpFile2.getName());
+            assertTrue(mTestDevice.doesFileExist(expectedDeviceFilePath2));
+
+            // verify 1st file timestamp did not change
+            String unchangedTmpFileStamp = mTestDevice.executeShellCommand(String.format("ls -l %s",
+                    expectedDeviceFilePath));
+            assertEquals(origTmpFileStamp, unchangedTmpFileStamp);
+
+            // now modify 1st file and verify it does change remotely
+            String testString = "blah";
+            FileOutputStream stream = new FileOutputStream(tmpFile);
+            stream.write(testString.getBytes());
+            stream.close();
+
+            // adjust 1st file's last-modified timestamp according to persist.sys.timezone
+            String deviceTimezone = mTestDevice.getProperty("persist.sys.timezone");
+            if (deviceTimezone != null) {
+                TimeZone tz = TimeZone.getTimeZone(deviceTimezone);
+                long timestamp = tmpFile.lastModified() + tz.getRawOffset();
+                if (tz.observesDaylightTime()) {
+                    timestamp += tz.getDSTSavings();
+                }
+                tmpFile.setLastModified(timestamp);
+            }
+
+            assertTrue(mTestDevice.syncFiles(tmpDir, externalStorePath));
+            String tmpFileContents = mTestDevice.executeShellCommand(String.format("cat %s",
+                    expectedDeviceFilePath));
+            assertTrue(tmpFileContents.contains(testString));
+        } finally {
+            if (expectedDeviceFilePath != null && externalStorePath != null) {
+                // note that expectedDeviceFilePath has externalStorePath prepended at definition
+                mTestDevice.executeShellCommand(String.format("rm -r %s", expectedDeviceFilePath));
+            }
+            FileUtil.recursiveDelete(tmpDir);
+        }
+    }
+
+    /**
+     * Test pushing a directory
+     */
+    public void testPushDir() throws IOException, DeviceNotAvailableException {
+        String expectedDeviceFilePath = null;
+        String externalStorePath = null;
+        File rootDir = FileUtil.createTempDir("tmp");
+        // create temp dir with one temp file
+        try {
+            File tmpDir = FileUtil.createTempDir("tmp", rootDir);
+            File tmpFile = createTempTestFile(tmpDir);
+            externalStorePath = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
+            assertNotNull(externalStorePath);
+            expectedDeviceFilePath = String.format("%s/%s/%s", externalStorePath,
+                    tmpDir.getName(), tmpFile.getName());
+
+            assertTrue(mTestDevice.pushDir(rootDir, externalStorePath));
+            assertTrue(mTestDevice.doesFileExist(expectedDeviceFilePath));
+
+        } finally {
+            if (expectedDeviceFilePath != null && externalStorePath != null) {
+                mTestDevice.executeShellCommand(String.format("rm -r %s/%s", externalStorePath,
+                        expectedDeviceFilePath));
+            }
+            FileUtil.recursiveDelete(rootDir);
+        }
+    }
+
+    /**
+     * Basic test for {@link TestDevice#getScreenshot()}.
+     * <p/>
+     * Grab a screenshot and perform a cursory size check to ensure its valid.
+     */
+    public void testGetScreenshot() throws DeviceNotAvailableException, IOException {
+        InputStreamSource source = getDevice().getScreenshot();
+        assertNotNull(source);
+        InputStream inputStream = source.createInputStream();
+        try {
+            BufferedImage screenshotImage = ImageIO.read(inputStream);
+            CLog.i(LOG_TAG, "testGetScreenshot w=%d, h=%d",
+                    screenshotImage.getWidth(), screenshotImage.getHeight());
+            assertTrue(screenshotImage.getWidth() > 0);
+            assertTrue(screenshotImage.getHeight() > 0);
+        } finally {
+            StreamUtil.cancel(source);
+            StreamUtil.close(inputStream);
+        }
+    }
+
+    /**
+     * Basic test for {@link TestDevice#getLogcat(long)}.
+     * <p/>
+     * Dumps a bunch of messages to logcat, calls getLogcat(), and verifies size of capture file is
+     * equal to provided data.
+     */
+    public void testGetLogcat_size() throws DeviceNotAvailableException, IOException {
+        CLog.i(LOG_TAG, "testGetLogcat_size");
+        for (int i = 0; i < 100; i++) {
+            getDevice().executeShellCommand(String.format("log testGetLogcat_size log dump %d", i));
+        }
+        boolean passed = false;
+        int retry = 0;
+        while (!passed) {
+            // sleep a small amount of time to ensure last log message makes it into capture
+            RunUtil.getDefault().sleep(10);
+            InputStreamSource source = getDevice().getLogcat(100 * 1024);
+            assertNotNull(source);
+            File tmpTxtFile = FileUtil.createTempFile("logcat", ".txt");
+            try {
+                FileUtil.writeToFile(source.createInputStream(), tmpTxtFile);
+                CLog.i("Created file at %s", tmpTxtFile.getAbsolutePath());
+                // ensure last log message is present in log
+                String s = FileUtil.readStringFromFile(tmpTxtFile);
+                if (s.contains("testGetLogcat_size log dump 99")) {
+                    passed = true;
+                }
+            } finally {
+                FileUtil.deleteFile(tmpTxtFile);
+                source.cancel();
+            }
+            retry++;
+            if ((retry > 100) && !passed) {
+                fail("last log message is not in captured logcat");
+            }
+        }
+    }
+}
diff --git a/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java b/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java
new file mode 100644
index 0000000..f5872a7
--- /dev/null
+++ b/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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 android.aadb.cts;
+
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.util.FileUtil;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Long running functional tests for {@link TestDevice} that verify an operation can be run
+ * many times in sequence
+ * <p/>
+ * Requires a physical device to be connected.
+ */
+public class TestDeviceStressTest extends DeviceTestCase {
+
+    private int mIterations = 25;
+
+    private static final String LOG_TAG = "TestDeviceStressTest";
+    private static final int TEST_FILE_COUNT= 200;
+    private ITestDevice mTestDevice;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTestDevice = getDevice();
+    }
+
+    private File createTempTestFiles() throws IOException {
+        File tmpDir = null;
+        File tmpFile = null;
+
+        tmpDir = FileUtil.createTempDir("testDir");
+
+        final String fileContents = "this is the test file contents";
+        for (int i = 0; i < TEST_FILE_COUNT; i++) {
+            tmpFile = FileUtil.createTempFile(String.format("tmp_%d", i), ".txt", tmpDir);
+            FileUtil.writeToFile(fileContents, tmpFile);
+        }
+        return tmpDir;
+
+    }
+
+    /**
+     * Stress test to push a folder which contains 200 text file to device
+     * internal storage.
+     */
+    public void testPushFolderWithManyFiles() throws IOException, DeviceNotAvailableException {
+        File tmpDir = null;
+        String deviceFilePath = null;
+        String externalStorePath = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
+        assertNotNull(externalStorePath);
+        deviceFilePath = String.format("%s/%s", externalStorePath, "testDir");
+
+        // start the stress test
+        try {
+            // Create the test folder and make sure the test folder doesn't exist in
+            // device before the test start.
+            tmpDir = createTempTestFiles();
+            for (int i = 0; i < mIterations; i++) {
+                mTestDevice.executeShellCommand(String.format("rm -r %s", deviceFilePath));
+                assertFalse(String.format("%s exists", deviceFilePath),
+                        mTestDevice.doesFileExist(deviceFilePath));
+                assertTrue(mTestDevice.pushDir(tmpDir, deviceFilePath));
+                assertTrue(mTestDevice.doesFileExist(deviceFilePath));
+            }
+        } finally {
+            if (tmpDir != null) {
+                FileUtil.recursiveDelete(tmpDir);
+            }
+            mTestDevice.executeShellCommand(String.format("rm -r %s", deviceFilePath));
+            assertFalse(String.format("%s exists", deviceFilePath),
+                    mTestDevice.doesFileExist(deviceFilePath));
+        }
+    }
+}
diff --git a/hostsidetests/aadb/src/com/android/cts/aadb/TestDeviceFuncTest.java b/hostsidetests/aadb/src/com/android/cts/aadb/TestDeviceFuncTest.java
deleted file mode 100644
index b0fb1fb..0000000
--- a/hostsidetests/aadb/src/com/android/cts/aadb/TestDeviceFuncTest.java
+++ /dev/null
@@ -1,404 +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.aadb;
-
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.IFileEntry;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.result.CollectingTestListener;
-import com.android.tradefed.result.InputStreamSource;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.util.CommandStatus;
-import com.android.tradefed.util.FileUtil;
-import com.android.tradefed.util.RunUtil;
-import com.android.tradefed.util.StreamUtil;
-
-import java.awt.image.BufferedImage;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.TimeZone;
-
-import javax.imageio.ImageIO;
-
-/**
- * Functional tests for adb connection
- * <p/>
- * Requires a physical device to be connected.
- */
-public class TestDeviceFuncTest extends DeviceTestCase {
-
-    private static final String LOG_TAG = "TestDeviceFuncTest";
-    private ITestDevice mTestDevice;
-    /** Expect bugreports to be at least a meg. */
-    private static final int mMinBugreportBytes = 1024 * 1024;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestDevice = getDevice();
-    }
-
-    /**
-     * Simple testcase to ensure that the grabbing a bugreport from a real TestDevice works.
-     */
-    public void testBugreport() throws Exception {
-        String data = StreamUtil.getStringFromStream(
-                mTestDevice.getBugreport().createInputStream());
-        assertTrue(String.format("Expected at least %d characters; only saw %d", mMinBugreportBytes,
-                data.length()), data.length() >= mMinBugreportBytes);
-        // TODO: check the captured report more extensively, perhaps using loganalysis
-    }
-
-    /**
-     * Simple normal case test for
-     * {@link TestDevice#executeShellCommand(String)}.
-     * <p/>
-     * Do a 'shell ls' command, and verify /data and /system are listed in result.
-     */
-    public void testExecuteShellCommand() throws IOException, DeviceNotAvailableException {
-        Log.i(LOG_TAG, "testExecuteShellCommand");
-        assertSimpleShellCommand();
-    }
-
-    /**
-     * Verify that a simple {@link TestDevice#executeShellCommand(String)} command is successful.
-     */
-    private void assertSimpleShellCommand() throws DeviceNotAvailableException {
-    	// Check for expected contents of device's root directory
-        final String output = mTestDevice.executeShellCommand("ls /");
-        assertTrue(output.contains("data"));
-        assertTrue(output.contains("system"));
-    }
-
-
-    /**
-     * Push and then pull a file from device, and verify contents are as expected.
-     */
-    public void testPushPull_normal() throws IOException, DeviceNotAvailableException {
-        Log.i(LOG_TAG, "testPushPull");
-        File tmpFile = null;
-        File tmpDestFile = null;
-        String deviceFilePath = null;
-
-        try {
-            tmpFile = createTempTestFile(null);
-            String externalStorePath = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
-            assertNotNull(externalStorePath);
-            deviceFilePath = String.format("%s/%s", externalStorePath, "tmp_testPushPull.txt");
-            // ensure file does not already exist
-            mTestDevice.executeShellCommand(String.format("rm %s", deviceFilePath));
-            assertFalse(String.format("%s exists", deviceFilePath),
-                    mTestDevice.doesFileExist(deviceFilePath));
-
-            assertTrue(mTestDevice.pushFile(tmpFile, deviceFilePath));
-            assertTrue(mTestDevice.doesFileExist(deviceFilePath));
-            tmpDestFile = FileUtil.createTempFile("tmp", "txt");
-            assertTrue(mTestDevice.pullFile(deviceFilePath, tmpDestFile));
-            assertTrue(compareFiles(tmpFile, tmpDestFile));
-        } finally {
-            if (tmpDestFile != null) {
-                tmpDestFile.delete();
-            }
-            if (deviceFilePath != null) {
-                mTestDevice.executeShellCommand(String.format("rm %s", deviceFilePath));
-            }
-        }
-    }
-
-    /**
-     * Push and then pull a file from device, and verify contents are as expected.
-     * <p />
-     * This variant of the test uses "${EXTERNAL_STORAGE}" in the pathname.
-     */
-    public void testPushPull_extStorageVariable() throws IOException, DeviceNotAvailableException {
-        Log.i(LOG_TAG, "testPushPull");
-        File tmpFile = null;
-        File tmpDestFile = null;
-        File tmpDestFile2 = null;
-        String deviceFilePath = null;
-        final String filename = "tmp_testPushPull.txt";
-
-        try {
-            tmpFile = createTempTestFile(null);
-            String externalStorePath = "${EXTERNAL_STORAGE}";
-            assertNotNull(externalStorePath);
-            deviceFilePath = String.format("%s/%s", externalStorePath, filename);
-            // ensure file does not already exist
-            mTestDevice.executeShellCommand(String.format("rm %s", deviceFilePath));
-            assertFalse(String.format("%s exists", deviceFilePath),
-                    mTestDevice.doesFileExist(deviceFilePath));
-
-            assertTrue(mTestDevice.pushFile(tmpFile, deviceFilePath));
-            assertTrue(mTestDevice.doesFileExist(deviceFilePath));
-            tmpDestFile = FileUtil.createTempFile("tmp", "txt");
-            assertTrue(mTestDevice.pullFile(deviceFilePath, tmpDestFile));
-            assertTrue(compareFiles(tmpFile, tmpDestFile));
-
-            tmpDestFile2 = mTestDevice.pullFileFromExternal(filename);
-            assertNotNull(tmpDestFile2);
-            assertTrue(compareFiles(tmpFile, tmpDestFile2));
-        } finally {
-            if (tmpDestFile != null) {
-                tmpDestFile.delete();
-            }
-            if (tmpDestFile2 != null) {
-                tmpDestFile2.delete();
-            }
-            if (deviceFilePath != null) {
-                mTestDevice.executeShellCommand(String.format("rm %s", deviceFilePath));
-            }
-        }
-    }
-
-    /**
-     * Test pulling a file from device that does not exist.
-     * <p/>
-     * Expect {@link TestDevice#pullFile(String)} to return <code>false</code>
-     */
-    public void testPull_noexist() throws IOException, DeviceNotAvailableException {
-        Log.i(LOG_TAG, "testPull_noexist");
-
-        // make sure the root path is valid
-        String externalStorePath =  mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
-        assertNotNull(externalStorePath);
-        String deviceFilePath = String.format("%s/%s", externalStorePath, "thisfiledoesntexist");
-        assertFalse(String.format("%s exists", deviceFilePath),
-                mTestDevice.doesFileExist(deviceFilePath));
-        assertNull(mTestDevice.pullFile(deviceFilePath));
-    }
-
-    private File createTempTestFile(File dir) throws IOException {
-        File tmpFile = null;
-        try {
-            final String fileContents = "this is the test file contents";
-            tmpFile = FileUtil.createTempFile("tmp", ".txt", dir);
-            FileUtil.writeToFile(fileContents, tmpFile);
-            return tmpFile;
-        } catch (IOException e) {
-            if (tmpFile != null) {
-                tmpFile.delete();
-            }
-            throw e;
-        }
-    }
-
-    /**
-     * Utility method to do byte-wise content comparison of two files.
-     */
-    private boolean compareFiles(File file1, File file2) throws IOException {
-        BufferedInputStream stream1 = null;
-        BufferedInputStream stream2 = null;
-
-        try {
-            stream1 = new BufferedInputStream(new FileInputStream(file1));
-            stream2 = new BufferedInputStream(new FileInputStream(file2));
-            boolean eof = false;
-            while (!eof) {
-                int byte1 = stream1.read();
-                int byte2 = stream2.read();
-                if (byte1 != byte2) {
-                    return false;
-                }
-                eof = byte1 == -1;
-            }
-            return true;
-        } finally {
-            if (stream1 != null) {
-                stream1.close();
-            }
-            if (stream2 != null) {
-                stream2.close();
-            }
-        }
-    }
-
-    /**
-     * Test syncing a single file using {@link TestDevice#syncFiles(File, String)}.
-     */
-    public void testSyncFiles_normal() throws Exception {
-        doTestSyncFiles(mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE));
-    }
-
-    /**
-     * Test syncing a single file using {@link TestDevice#syncFiles(File, String)}.
-     * <p />
-     * This variant of the test uses "${EXTERNAL_STORAGE}" in the pathname.
-     */
-    public void testSyncFiles_extStorageVariable() throws Exception {
-        doTestSyncFiles("${EXTERNAL_STORAGE}");
-    }
-
-    /**
-     * Test syncing a single file using {@link TestDevice#syncFiles(File, String)}.
-     */
-    public void doTestSyncFiles(String externalStorePath) throws Exception {
-        String expectedDeviceFilePath = null;
-
-        // create temp dir with one temp file
-        File tmpDir = FileUtil.createTempDir("tmp");
-        try {
-            File tmpFile = createTempTestFile(tmpDir);
-            // set last modified to 10 minutes ago
-            tmpFile.setLastModified(System.currentTimeMillis() - 10*60*1000);
-            assertNotNull(externalStorePath);
-            expectedDeviceFilePath = String.format("%s/%s/%s", externalStorePath,
-                    tmpDir.getName(), tmpFile.getName());
-
-            assertTrue(mTestDevice.syncFiles(tmpDir, externalStorePath));
-            assertTrue(mTestDevice.doesFileExist(expectedDeviceFilePath));
-
-            // get 'ls -l' attributes of file which includes timestamp
-            String origTmpFileStamp = mTestDevice.executeShellCommand(String.format("ls -l %s",
-                    expectedDeviceFilePath));
-            // now create another file and verify that is synced
-            File tmpFile2 = createTempTestFile(tmpDir);
-            tmpFile2.setLastModified(System.currentTimeMillis() - 10*60*1000);
-            assertTrue(mTestDevice.syncFiles(tmpDir, externalStorePath));
-            String expectedDeviceFilePath2 = String.format("%s/%s/%s", externalStorePath,
-                    tmpDir.getName(), tmpFile2.getName());
-            assertTrue(mTestDevice.doesFileExist(expectedDeviceFilePath2));
-
-            // verify 1st file timestamp did not change
-            String unchangedTmpFileStamp = mTestDevice.executeShellCommand(String.format("ls -l %s",
-                    expectedDeviceFilePath));
-            assertEquals(origTmpFileStamp, unchangedTmpFileStamp);
-
-            // now modify 1st file and verify it does change remotely
-            String testString = "blah";
-            FileOutputStream stream = new FileOutputStream(tmpFile);
-            stream.write(testString.getBytes());
-            stream.close();
-
-            // adjust 1st file's last-modified timestamp according to persist.sys.timezone
-            String deviceTimezone = mTestDevice.getProperty("persist.sys.timezone");
-            if (deviceTimezone != null) {
-                TimeZone tz = TimeZone.getTimeZone(deviceTimezone);
-                long timestamp = tmpFile.lastModified() + tz.getRawOffset();
-                if (tz.observesDaylightTime()) {
-                    timestamp += tz.getDSTSavings();
-                }
-                tmpFile.setLastModified(timestamp);
-            }
-
-            assertTrue(mTestDevice.syncFiles(tmpDir, externalStorePath));
-            String tmpFileContents = mTestDevice.executeShellCommand(String.format("cat %s",
-                    expectedDeviceFilePath));
-            assertTrue(tmpFileContents.contains(testString));
-        } finally {
-            if (expectedDeviceFilePath != null && externalStorePath != null) {
-                // note that expectedDeviceFilePath has externalStorePath prepended at definition
-                mTestDevice.executeShellCommand(String.format("rm -r %s", expectedDeviceFilePath));
-            }
-            FileUtil.recursiveDelete(tmpDir);
-        }
-    }
-
-    /**
-     * Test pushing a directory
-     */
-    public void testPushDir() throws IOException, DeviceNotAvailableException {
-        String expectedDeviceFilePath = null;
-        String externalStorePath = null;
-        File rootDir = FileUtil.createTempDir("tmp");
-        // create temp dir with one temp file
-        try {
-            File tmpDir = FileUtil.createTempDir("tmp", rootDir);
-            File tmpFile = createTempTestFile(tmpDir);
-            externalStorePath = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
-            assertNotNull(externalStorePath);
-            expectedDeviceFilePath = String.format("%s/%s/%s", externalStorePath,
-                    tmpDir.getName(), tmpFile.getName());
-
-            assertTrue(mTestDevice.pushDir(rootDir, externalStorePath));
-            assertTrue(mTestDevice.doesFileExist(expectedDeviceFilePath));
-
-        } finally {
-            if (expectedDeviceFilePath != null && externalStorePath != null) {
-                mTestDevice.executeShellCommand(String.format("rm -r %s/%s", externalStorePath,
-                        expectedDeviceFilePath));
-            }
-            FileUtil.recursiveDelete(rootDir);
-        }
-    }
-
-    /**
-     * Basic test for {@link TestDevice#getScreenshot()}.
-     * <p/>
-     * Grab a screenshot and perform a cursory size check to ensure its valid.
-     */
-    public void testGetScreenshot() throws DeviceNotAvailableException, IOException {
-        InputStreamSource source = getDevice().getScreenshot();
-        assertNotNull(source);
-        InputStream inputStream = source.createInputStream();
-        try {
-            BufferedImage screenshotImage = ImageIO.read(inputStream);
-            CLog.i(LOG_TAG, "testGetScreenshot w=%d, h=%d",
-                    screenshotImage.getWidth(), screenshotImage.getHeight());
-            assertTrue(screenshotImage.getWidth() > 0);
-            assertTrue(screenshotImage.getHeight() > 0);
-        } finally {
-            StreamUtil.cancel(source);
-            StreamUtil.close(inputStream);
-        }
-    }
-
-    /**
-     * Basic test for {@link TestDevice#getLogcat(long)}.
-     * <p/>
-     * Dumps a bunch of messages to logcat, calls getLogcat(), and verifies size of capture file is
-     * equal to provided data.
-     */
-    public void testGetLogcat_size() throws DeviceNotAvailableException, IOException {
-        CLog.i(LOG_TAG, "testGetLogcat_size");
-        for (int i = 0; i < 100; i++) {
-            getDevice().executeShellCommand(String.format("log testGetLogcat_size log dump %d", i));
-        }
-        boolean passed = false;
-        int retry = 0;
-        while (!passed) {
-            // sleep a small amount of time to ensure last log message makes it into capture
-            RunUtil.getDefault().sleep(10);
-            InputStreamSource source = getDevice().getLogcat(100 * 1024);
-            assertNotNull(source);
-            File tmpTxtFile = FileUtil.createTempFile("logcat", ".txt");
-            try {
-                FileUtil.writeToFile(source.createInputStream(), tmpTxtFile);
-                CLog.i("Created file at %s", tmpTxtFile.getAbsolutePath());
-                // ensure last log message is present in log
-                String s = FileUtil.readStringFromFile(tmpTxtFile);
-                if (s.contains("testGetLogcat_size log dump 99")) {
-                    passed = true;
-                }
-            } finally {
-                FileUtil.deleteFile(tmpTxtFile);
-                source.cancel();
-            }
-            retry++;
-            if ((retry > 100) && !passed) {
-                fail("last log message is not in captured logcat");
-            }
-        }
-    }
-}
diff --git a/hostsidetests/aadb/src/com/android/cts/aadb/TestDeviceStressTest.java b/hostsidetests/aadb/src/com/android/cts/aadb/TestDeviceStressTest.java
deleted file mode 100644
index 2c6fcef..0000000
--- a/hostsidetests/aadb/src/com/android/cts/aadb/TestDeviceStressTest.java
+++ /dev/null
@@ -1,98 +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.aadb;
-
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
-import com.android.tradefed.config.Option;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.result.CollectingTestListener;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.util.FileUtil;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Long running functional tests for {@link TestDevice} that verify an operation can be run
- * many times in sequence
- * <p/>
- * Requires a physical device to be connected.
- */
-public class TestDeviceStressTest extends DeviceTestCase {
-
-    private int mIterations = 25;
-
-    private static final String LOG_TAG = "TestDeviceStressTest";
-    private static final int TEST_FILE_COUNT= 200;
-    private ITestDevice mTestDevice;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestDevice = getDevice();
-    }
-
-    private File createTempTestFiles() throws IOException {
-        File tmpDir = null;
-        File tmpFile = null;
-
-        tmpDir = FileUtil.createTempDir("testDir");
-
-        final String fileContents = "this is the test file contents";
-        for (int i = 0; i < TEST_FILE_COUNT; i++) {
-            tmpFile = FileUtil.createTempFile(String.format("tmp_%d", i), ".txt", tmpDir);
-            FileUtil.writeToFile(fileContents, tmpFile);
-        }
-        return tmpDir;
-
-    }
-
-    /**
-     * Stress test to push a folder which contains 200 text file to device
-     * internal storage.
-     */
-    public void testPushFolderWithManyFiles() throws IOException, DeviceNotAvailableException {
-        File tmpDir = null;
-        String deviceFilePath = null;
-        String externalStorePath = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
-        assertNotNull(externalStorePath);
-        deviceFilePath = String.format("%s/%s", externalStorePath, "testDir");
-
-        // start the stress test
-        try {
-            // Create the test folder and make sure the test folder doesn't exist in
-            // device before the test start.
-            tmpDir = createTempTestFiles();
-            for (int i = 0; i < mIterations; i++) {
-                mTestDevice.executeShellCommand(String.format("rm -r %s", deviceFilePath));
-                assertFalse(String.format("%s exists", deviceFilePath),
-                        mTestDevice.doesFileExist(deviceFilePath));
-                assertTrue(mTestDevice.pushDir(tmpDir, deviceFilePath));
-                assertTrue(mTestDevice.doesFileExist(deviceFilePath));
-            }
-        } finally {
-            if (tmpDir != null) {
-                FileUtil.recursiveDelete(tmpDir);
-            }
-            mTestDevice.executeShellCommand(String.format("rm -r %s", deviceFilePath));
-            assertFalse(String.format("%s exists", deviceFilePath),
-                    mTestDevice.doesFileExist(deviceFilePath));
-        }
-    }
-}
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index 61f9a4d..55fe0d9 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -19,11 +19,16 @@
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_MODULE := CtsAppSecurityTests
+LOCAL_MODULE := CtsAppSecurityHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
 
-LOCAL_CTS_TEST_PACKAGE := android.tests.appsecurity
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+
+LOCAL_CTS_TEST_PACKAGE := android.appsecurity
+
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/appsecurity/AndroidTest.xml b/hostsidetests/appsecurity/AndroidTest.xml
new file mode 100644
index 0000000..d1989e6
--- /dev/null
+++ b/hostsidetests/appsecurity/AndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for the CTS App Security host tests">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsAppSecurityHostTestCases.jar" />
+        <option name="runtime-hint" value="20m" />
+    </test>
+</configuration>
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
new file mode 100644
index 0000000..d8c2134
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2015 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.appsecurity.cts;
+
+import static android.appsecurity.cts.SplitTests.ABI_TO_APK;
+import static android.appsecurity.cts.SplitTests.APK;
+import static android.appsecurity.cts.SplitTests.APK_mdpi;
+import static android.appsecurity.cts.SplitTests.APK_xxhdpi;
+import static android.appsecurity.cts.SplitTests.CLASS;
+import static android.appsecurity.cts.SplitTests.PKG;
+
+import android.appsecurity.cts.SplitTests.BaseInstallMultiple;
+import com.android.cts.migration.MigrationHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.util.Arrays;
+
+/**
+ * Set of tests that verify behavior of adopted storage media, if supported.
+ */
+public class AdoptableHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+    private IAbi mAbi;
+    private IBuildInfo mCtsBuild;
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        assertNotNull(mAbi);
+        assertNotNull(mCtsBuild);
+
+        getDevice().uninstallPackage(PKG);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        getDevice().uninstallPackage(PKG);
+    }
+
+    public void testApps() throws Exception {
+        if (!hasAdoptable()) return;
+        final String diskId = getAdoptionDisk();
+        try {
+            final String abi = mAbi.getName();
+            final String apk = ABI_TO_APK.get(abi);
+            assertNotNull("Failed to find APK for ABI " + abi, apk);
+
+            // Install simple app on internal
+            new InstallMultiple().useNaturalAbi().addApk(APK).addApk(apk).run();
+            runDeviceTests(PKG, CLASS, "testDataInternal");
+            runDeviceTests(PKG, CLASS, "testDataWrite");
+            runDeviceTests(PKG, CLASS, "testDataRead");
+            runDeviceTests(PKG, CLASS, "testNative");
+
+            // Adopt that disk!
+            assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
+            final LocalVolumeInfo vol = getAdoptionVolume();
+
+            // Move app and verify
+            assertSuccess(getDevice().executeShellCommand(
+                    "pm move-package " + PKG + " " + vol.uuid));
+            runDeviceTests(PKG, CLASS, "testDataNotInternal");
+            runDeviceTests(PKG, CLASS, "testDataRead");
+            runDeviceTests(PKG, CLASS, "testNative");
+
+            // Unmount, remount and verify
+            getDevice().executeShellCommand("sm unmount " + vol.volId);
+            getDevice().executeShellCommand("sm mount " + vol.volId);
+            runDeviceTests(PKG, CLASS, "testDataNotInternal");
+            runDeviceTests(PKG, CLASS, "testDataRead");
+            runDeviceTests(PKG, CLASS, "testNative");
+
+            // Move app back and verify
+            assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " internal"));
+            runDeviceTests(PKG, CLASS, "testDataInternal");
+            runDeviceTests(PKG, CLASS, "testDataRead");
+            runDeviceTests(PKG, CLASS, "testNative");
+
+            // Un-adopt volume and app should still be fine
+            getDevice().executeShellCommand("sm partition " + diskId + " public");
+            runDeviceTests(PKG, CLASS, "testDataInternal");
+            runDeviceTests(PKG, CLASS, "testDataRead");
+            runDeviceTests(PKG, CLASS, "testNative");
+
+        } finally {
+            cleanUp(diskId);
+        }
+    }
+
+    public void testPrimaryStorage() throws Exception {
+        if (!hasAdoptable()) return;
+        final String diskId = getAdoptionDisk();
+        try {
+            final String originalVol = getDevice()
+                    .executeShellCommand("sm get-primary-storage-uuid").trim();
+
+            if ("null".equals(originalVol)) {
+                verifyPrimaryInternal(diskId);
+            } else if ("primary_physical".equals(originalVol)) {
+                verifyPrimaryPhysical(diskId);
+            }
+        } finally {
+            cleanUp(diskId);
+        }
+    }
+
+    private void verifyPrimaryInternal(String diskId) throws Exception {
+        // Write some data to shared storage
+        new InstallMultiple().addApk(APK).run();
+        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
+        runDeviceTests(PKG, CLASS, "testPrimaryInternal");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataWrite");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+
+        // Adopt that disk!
+        assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
+        final LocalVolumeInfo vol = getAdoptionVolume();
+
+        // Move storage there and verify that data went along for ride
+        assertSuccess(getDevice().executeShellCommand("pm move-primary-storage " + vol.uuid));
+        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+
+        // Unmount and verify
+        getDevice().executeShellCommand("sm unmount " + vol.volId);
+        runDeviceTests(PKG, CLASS, "testPrimaryUnmounted");
+        getDevice().executeShellCommand("sm mount " + vol.volId);
+        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+
+        // Move app and verify backing storage volume is same
+        assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " " + vol.uuid));
+        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+
+        // And move back to internal
+        assertSuccess(getDevice().executeShellCommand("pm move-primary-storage internal"));
+        runDeviceTests(PKG, CLASS, "testPrimaryInternal");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+
+        assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " internal"));
+        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+    }
+
+    private void verifyPrimaryPhysical(String diskId) throws Exception {
+        // Write some data to shared storage
+        new InstallMultiple().addApk(APK).run();
+        runDeviceTests(PKG, CLASS, "testPrimaryPhysical");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataWrite");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+
+        // Adopt that disk!
+        assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
+        final LocalVolumeInfo vol = getAdoptionVolume();
+
+        // Move primary storage there, but since we just nuked primary physical
+        // the storage device will be empty
+        assertSuccess(getDevice().executeShellCommand("pm move-primary-storage " + vol.uuid));
+        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataWrite");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+
+        // Unmount and verify
+        getDevice().executeShellCommand("sm unmount " + vol.volId);
+        runDeviceTests(PKG, CLASS, "testPrimaryUnmounted");
+        getDevice().executeShellCommand("sm mount " + vol.volId);
+        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+
+        // And move to internal
+        assertSuccess(getDevice().executeShellCommand("pm move-primary-storage internal"));
+        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
+        runDeviceTests(PKG, CLASS, "testPrimaryInternal");
+        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
+    }
+
+    /**
+     * Verify that we can install both new and inherited packages directly on
+     * adopted volumes.
+     */
+    public void testPackageInstaller() throws Exception {
+        if (!hasAdoptable()) return;
+        final String diskId = getAdoptionDisk();
+        try {
+            assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
+            final LocalVolumeInfo vol = getAdoptionVolume();
+
+            // Install directly onto adopted volume
+            new InstallMultiple().locationAuto().forceUuid(vol.uuid)
+                    .addApk(APK).addApk(APK_mdpi).run();
+            runDeviceTests(PKG, CLASS, "testDataNotInternal");
+            runDeviceTests(PKG, CLASS, "testDensityBest1");
+
+            // Now splice in an additional split which offers better resources
+            new InstallMultiple().locationAuto().inheritFrom(PKG)
+                    .addApk(APK_xxhdpi).run();
+            runDeviceTests(PKG, CLASS, "testDataNotInternal");
+            runDeviceTests(PKG, CLASS, "testDensityBest2");
+
+        } finally {
+            cleanUp(diskId);
+        }
+    }
+
+    /**
+     * Verify behavior when changes occur while adopted device is ejected and
+     * returned at a later time.
+     */
+    public void testEjected() throws Exception {
+        if (!hasAdoptable()) return;
+        final String diskId = getAdoptionDisk();
+        try {
+            assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
+            final LocalVolumeInfo vol = getAdoptionVolume();
+
+            // Install directly onto adopted volume, and write data there
+            new InstallMultiple().locationAuto().forceUuid(vol.uuid).addApk(APK).run();
+            runDeviceTests(PKG, CLASS, "testDataNotInternal");
+            runDeviceTests(PKG, CLASS, "testDataWrite");
+            runDeviceTests(PKG, CLASS, "testDataRead");
+
+            // Now unmount and uninstall; leaving stale package on adopted volume
+            getDevice().executeShellCommand("sm unmount " + vol.volId);
+            getDevice().uninstallPackage(PKG);
+
+            // Install second copy on internal, but don't write anything
+            new InstallMultiple().locationInternalOnly().addApk(APK).run();
+            runDeviceTests(PKG, CLASS, "testDataInternal");
+
+            // Kick through a remount cycle, which should purge the adopted app
+            getDevice().executeShellCommand("sm mount " + vol.volId);
+            runDeviceTests(PKG, CLASS, "testDataInternal");
+            try {
+                runDeviceTests(PKG, CLASS, "testDataRead");
+                fail("Unexpected data from adopted volume picked up");
+            } catch (AssertionError expected) {
+            }
+            getDevice().executeShellCommand("sm unmount " + vol.volId);
+
+            // Uninstall the internal copy and remount; we should have no record of app
+            getDevice().uninstallPackage(PKG);
+            getDevice().executeShellCommand("sm mount " + vol.volId);
+
+            assertEmpty(getDevice().executeShellCommand("pm list packages " + PKG));
+        } finally {
+            cleanUp(diskId);
+        }
+    }
+
+    private boolean hasAdoptable() throws Exception {
+        return Boolean.parseBoolean(getDevice().executeShellCommand("sm has-adoptable").trim());
+    }
+
+    private String getAdoptionDisk() throws Exception {
+        final String disks = getDevice().executeShellCommand("sm list-disks adoptable");
+        if (disks == null || disks.length() == 0) {
+            throw new AssertionError("Devices that claim to support adoptable storage must have "
+                    + "adoptable media inserted during CTS to verify correct behavior");
+        }
+        return disks.split("\n")[0].trim();
+    }
+
+    private LocalVolumeInfo getAdoptionVolume() throws Exception {
+        String[] lines = null;
+        int attempt = 0;
+        while (attempt++ < 15) {
+            lines = getDevice().executeShellCommand("sm list-volumes private").split("\n");
+            for (String line : lines) {
+                final LocalVolumeInfo info = new LocalVolumeInfo(line.trim());
+                if (!"private".equals(info.volId) && "mounted".equals(info.state)) {
+                    return info;
+                }
+            }
+            Thread.sleep(1000);
+        }
+        throw new AssertionError("Expected private volume; found " + Arrays.toString(lines));
+    }
+
+    private void cleanUp(String diskId) throws Exception {
+        getDevice().executeShellCommand("sm partition " + diskId + " public");
+        getDevice().executeShellCommand("sm forget all");
+    }
+
+    private void runDeviceTests(String packageName, String testClassName, String testMethodName)
+            throws DeviceNotAvailableException {
+        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
+    }
+
+    private static void assertSuccess(String str) {
+        if (str == null || !str.startsWith("Success")) {
+            throw new AssertionError("Expected success string but found " + str);
+        }
+    }
+
+    private static void assertEmpty(String str) {
+        if (str != null && str.trim().length() > 0) {
+            throw new AssertionError("Expected empty string but found " + str);
+        }
+    }
+
+    private static class LocalVolumeInfo {
+        public String volId;
+        public String state;
+        public String uuid;
+
+        public LocalVolumeInfo(String line) {
+            final String[] split = line.split(" ");
+            volId = split[0];
+            state = split[1];
+            uuid = split[2];
+        }
+    }
+
+    private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+        public InstallMultiple() {
+            super(getDevice(), mCtsBuild, mAbi);
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
new file mode 100644
index 0000000..00acdf5
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2009 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.appsecurity.cts;
+
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.cts.migration.MigrationHelper;
+import com.android.ddmlib.Log;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * Set of tests that verify various security checks involving multiple apps are
+ * properly enforced.
+ */
+public class AppSecurityTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+
+    // testSharedUidDifferentCerts constants
+    private static final String SHARED_UI_APK = "CtsSharedUidInstall.apk";
+    private static final String SHARED_UI_PKG = "com.android.cts.shareuidinstall";
+    private static final String SHARED_UI_DIFF_CERT_APK = "CtsSharedUidInstallDiffCert.apk";
+    private static final String SHARED_UI_DIFF_CERT_PKG =
+        "com.android.cts.shareuidinstalldiffcert";
+
+    // testAppUpgradeDifferentCerts constants
+    private static final String SIMPLE_APP_APK = "CtsSimpleAppInstall.apk";
+    private static final String SIMPLE_APP_PKG = "com.android.cts.simpleappinstall";
+    private static final String SIMPLE_APP_DIFF_CERT_APK = "CtsSimpleAppInstallDiffCert.apk";
+
+    // testAppFailAccessPrivateData constants
+    private static final String APP_WITH_DATA_APK = "CtsAppWithData.apk";
+    private static final String APP_WITH_DATA_PKG = "com.android.cts.appwithdata";
+    private static final String APP_WITH_DATA_CLASS =
+            "com.android.cts.appwithdata.CreatePrivateDataTest";
+    private static final String APP_WITH_DATA_CREATE_METHOD =
+            "testCreatePrivateData";
+    private static final String APP_WITH_DATA_CHECK_NOEXIST_METHOD =
+            "testEnsurePrivateDataNotExist";
+    private static final String APP_ACCESS_DATA_APK = "CtsAppAccessData.apk";
+    private static final String APP_ACCESS_DATA_PKG = "com.android.cts.appaccessdata";
+
+    // testInstrumentationDiffCert constants
+    private static final String TARGET_INSTRUMENT_APK = "CtsTargetInstrumentationApp.apk";
+    private static final String TARGET_INSTRUMENT_PKG = "com.android.cts.targetinstrumentationapp";
+    private static final String INSTRUMENT_DIFF_CERT_APK = "CtsInstrumentationAppDiffCert.apk";
+    private static final String INSTRUMENT_DIFF_CERT_PKG =
+        "com.android.cts.instrumentationdiffcertapp";
+
+    // testPermissionDiffCert constants
+    private static final String DECLARE_PERMISSION_APK = "CtsPermissionDeclareApp.apk";
+    private static final String DECLARE_PERMISSION_PKG = "com.android.cts.permissiondeclareapp";
+    private static final String DECLARE_PERMISSION_COMPAT_APK = "CtsPermissionDeclareAppCompat.apk";
+    private static final String DECLARE_PERMISSION_COMPAT_PKG = "com.android.cts.permissiondeclareappcompat";
+
+    private static final String PERMISSION_DIFF_CERT_APK = "CtsUsePermissionDiffCert.apk";
+    private static final String PERMISSION_DIFF_CERT_PKG =
+        "com.android.cts.usespermissiondiffcertapp";
+
+    private static final String LOG_TAG = "AppSecurityTests";
+
+    private IAbi mAbi;
+    private IBuildInfo mCtsBuild;
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    private File getTestAppFile(String fileName) throws FileNotFoundException {
+        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // ensure build has been set before test is run
+        assertNotNull(mCtsBuild);
+    }
+
+    /**
+     * Test that an app that declares the same shared uid as an existing app, cannot be installed
+     * if it is signed with a different certificate.
+     */
+    public void testSharedUidDifferentCerts() throws Exception {
+        Log.i(LOG_TAG, "installing apks with shared uid, but different certs");
+        try {
+            // cleanup test apps that might be installed from previous partial test run
+            getDevice().uninstallPackage(SHARED_UI_PKG);
+            getDevice().uninstallPackage(SHARED_UI_DIFF_CERT_PKG);
+
+            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            String installResult = getDevice().installPackage(getTestAppFile(SHARED_UI_APK),
+                    false, options);
+            assertNull(String.format("failed to install shared uid app, Reason: %s", installResult),
+                    installResult);
+            installResult = getDevice().installPackage(getTestAppFile(SHARED_UI_DIFF_CERT_APK),
+                    false, options);
+            assertNotNull("shared uid app with different cert than existing app installed " +
+                    "successfully", installResult);
+            assertEquals("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE",
+                    installResult.substring(0, installResult.indexOf(':')));
+        } finally {
+            getDevice().uninstallPackage(SHARED_UI_PKG);
+            getDevice().uninstallPackage(SHARED_UI_DIFF_CERT_PKG);
+        }
+    }
+
+    /**
+     * Test that an app update cannot be installed over an existing app if it has a different
+     * certificate.
+     */
+    public void testAppUpgradeDifferentCerts() throws Exception {
+        Log.i(LOG_TAG, "installing app upgrade with different certs");
+        try {
+            // cleanup test app that might be installed from previous partial test run
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+
+            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            String installResult = getDevice().installPackage(getTestAppFile(SIMPLE_APP_APK),
+                    false, options);
+            assertNull(String.format("failed to install simple app. Reason: %s", installResult),
+                    installResult);
+            installResult = getDevice().installPackage(getTestAppFile(SIMPLE_APP_DIFF_CERT_APK),
+                    true /* reinstall */, options);
+            assertNotNull("app upgrade with different cert than existing app installed " +
+                    "successfully", installResult);
+            assertEquals("INSTALL_FAILED_UPDATE_INCOMPATIBLE",
+                    installResult.substring(0, installResult.indexOf(':')));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    /**
+     * Test that an app cannot access another app's private data.
+     */
+    public void testAppFailAccessPrivateData() throws Exception {
+        Log.i(LOG_TAG, "installing app that attempts to access another app's private data");
+        try {
+            // cleanup test app that might be installed from previous partial test run
+            getDevice().uninstallPackage(APP_WITH_DATA_PKG);
+            getDevice().uninstallPackage(APP_ACCESS_DATA_PKG);
+
+            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            String installResult = getDevice().installPackage(getTestAppFile(APP_WITH_DATA_APK),
+                    false, options);
+            assertNull(String.format("failed to install app with data. Reason: %s", installResult),
+                    installResult);
+            // run appwithdata's tests to create private data
+            runDeviceTests(APP_WITH_DATA_PKG, APP_WITH_DATA_CLASS, APP_WITH_DATA_CREATE_METHOD);
+
+            installResult = getDevice().installPackage(getTestAppFile(APP_ACCESS_DATA_APK),
+                    false, options);
+            assertNull(String.format("failed to install app access data. Reason: %s",
+                    installResult), installResult);
+            // run appaccessdata's tests which attempt to access appwithdata's private data
+            runDeviceTests(APP_ACCESS_DATA_PKG);
+        } finally {
+            getDevice().uninstallPackage(APP_WITH_DATA_PKG);
+            getDevice().uninstallPackage(APP_ACCESS_DATA_PKG);
+        }
+    }
+
+    /**
+     * Test that uninstall of an app removes its private data.
+     */
+    public void testUninstallRemovesData() throws Exception {
+        Log.i(LOG_TAG, "Uninstalling app, verifying data is removed.");
+        try {
+            // cleanup test app that might be installed from previous partial test run
+            getDevice().uninstallPackage(APP_WITH_DATA_PKG);
+
+            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            String installResult = getDevice().installPackage(getTestAppFile(APP_WITH_DATA_APK),
+                    false, options);
+            assertNull(String.format("failed to install app with data. Reason: %s", installResult),
+                    installResult);
+            // run appwithdata's tests to create private data
+            runDeviceTests(APP_WITH_DATA_PKG, APP_WITH_DATA_CLASS, APP_WITH_DATA_CREATE_METHOD);
+
+            getDevice().uninstallPackage(APP_WITH_DATA_PKG);
+
+            installResult = getDevice().installPackage(getTestAppFile(APP_WITH_DATA_APK),
+                    false, options);
+            assertNull(String.format("failed to install app with data second time. Reason: %s",
+                    installResult), installResult);
+            // run appwithdata's 'check if file exists' test
+            runDeviceTests(APP_WITH_DATA_PKG, APP_WITH_DATA_CLASS,
+                    APP_WITH_DATA_CHECK_NOEXIST_METHOD);
+        } finally {
+            getDevice().uninstallPackage(APP_WITH_DATA_PKG);
+        }
+    }
+
+    /**
+     * Test that an app cannot instrument another app that is signed with different certificate.
+     */
+    public void testInstrumentationDiffCert() throws Exception {
+        Log.i(LOG_TAG, "installing app that attempts to instrument another app");
+        try {
+            // cleanup test app that might be installed from previous partial test run
+            getDevice().uninstallPackage(TARGET_INSTRUMENT_PKG);
+            getDevice().uninstallPackage(INSTRUMENT_DIFF_CERT_PKG);
+
+            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            String installResult = getDevice().installPackage(
+                    getTestAppFile(TARGET_INSTRUMENT_APK), false, options);
+            assertNull(String.format("failed to install target instrumentation app. Reason: %s",
+                    installResult), installResult);
+
+            // the app will install, but will get error at runtime when starting instrumentation
+            installResult = getDevice().installPackage(getTestAppFile(INSTRUMENT_DIFF_CERT_APK),
+                    false, options);
+            assertNull(String.format(
+                    "failed to install instrumentation app with diff cert. Reason: %s",
+                    installResult), installResult);
+            // run INSTRUMENT_DIFF_CERT_PKG tests
+            // this test will attempt to call startInstrumentation directly and verify
+            // SecurityException is thrown
+            runDeviceTests(INSTRUMENT_DIFF_CERT_PKG);
+        } finally {
+            getDevice().uninstallPackage(TARGET_INSTRUMENT_PKG);
+            getDevice().uninstallPackage(INSTRUMENT_DIFF_CERT_PKG);
+        }
+    }
+
+    /**
+     * Test that an app cannot use a signature-enforced permission if it is signed with a different
+     * certificate than the app that declared the permission.
+     */
+    public void testPermissionDiffCert() throws Exception {
+        Log.i(LOG_TAG, "installing app that attempts to use permission of another app");
+        try {
+            // cleanup test app that might be installed from previous partial test run
+            getDevice().uninstallPackage(DECLARE_PERMISSION_PKG);
+            getDevice().uninstallPackage(DECLARE_PERMISSION_COMPAT_PKG);
+            getDevice().uninstallPackage(PERMISSION_DIFF_CERT_PKG);
+
+            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            String installResult = getDevice().installPackage(
+                    getTestAppFile(DECLARE_PERMISSION_APK), false, options);
+            assertNull(String.format("failed to install declare permission app. Reason: %s",
+                    installResult), installResult);
+
+            installResult = getDevice().installPackage(
+                    getTestAppFile(DECLARE_PERMISSION_COMPAT_APK), false, options);
+            assertNull(String.format("failed to install declare permission compat app. Reason: %s",
+                    installResult), installResult);
+
+            // the app will install, but will get error at runtime
+            installResult = getDevice().installPackage(getTestAppFile(PERMISSION_DIFF_CERT_APK),
+                    false, options);
+            assertNull(String.format("failed to install permission app with diff cert. Reason: %s",
+                    installResult), installResult);
+            // run PERMISSION_DIFF_CERT_PKG tests which try to access the permission
+            runDeviceTests(PERMISSION_DIFF_CERT_PKG);
+        } finally {
+            getDevice().uninstallPackage(DECLARE_PERMISSION_PKG);
+            getDevice().uninstallPackage(DECLARE_PERMISSION_COMPAT_PKG);
+            getDevice().uninstallPackage(PERMISSION_DIFF_CERT_PKG);
+        }
+    }
+
+    private void runDeviceTests(String packageName) throws DeviceNotAvailableException {
+        Utils.runDeviceTests(getDevice(), packageName);
+    }
+
+    private void runDeviceTests(String packageName, String testClassName, String testMethodName)
+            throws DeviceNotAvailableException {
+        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
new file mode 100644
index 0000000..300aa3a
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.appsecurity.cts;
+
+import com.android.cts.migration.MigrationHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+/**
+ * Set of tests that verify behavior of
+ * {@link android.provider.DocumentsContract} and related intents.
+ */
+public class DocumentsTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+    private static final String PROVIDER_PKG = "com.android.cts.documentprovider";
+    private static final String PROVIDER_APK = "CtsDocumentProvider.apk";
+
+    private static final String CLIENT_PKG = "com.android.cts.documentclient";
+    private static final String CLIENT_APK = "CtsDocumentClient.apk";
+
+    private IAbi mAbi;
+    private IBuildInfo mCtsBuild;
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        assertNotNull(mAbi);
+        assertNotNull(mCtsBuild);
+
+        getDevice().uninstallPackage(PROVIDER_PKG);
+        getDevice().uninstallPackage(CLIENT_PKG);
+
+        assertNull(getDevice().installPackage(
+                MigrationHelper.getTestFile(mCtsBuild, PROVIDER_APK), false));
+        assertNull(getDevice().installPackage(
+                MigrationHelper.getTestFile(mCtsBuild, CLIENT_APK), false));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        getDevice().uninstallPackage(PROVIDER_PKG);
+        getDevice().uninstallPackage(CLIENT_PKG);
+    }
+
+    public void testOpenSimple() throws Exception {
+        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testOpenSimple");
+    }
+
+    public void testCreateNew() throws Exception {
+        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testCreateNew");
+    }
+
+    public void testCreateExisting() throws Exception {
+        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testCreateExisting");
+    }
+
+    public void testTree() throws Exception {
+        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testTree");
+    }
+
+    public void testGetContent() throws Exception {
+        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testGetContent");
+    }
+
+    public void runDeviceTests(String packageName, String testClassName, String testMethodName)
+            throws DeviceNotAvailableException {
+        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
new file mode 100644
index 0000000..c49340e
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2015 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.appsecurity.cts;
+
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.cts.migration.MigrationHelper;
+import com.android.ddmlib.Log;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * Set of tests that verify behavior of external storage devices.
+ */
+public class ExternalStorageHostTest extends DeviceTestCase
+        implements IAbiReceiver, IBuildReceiver {
+    private static final String TAG = "ExternalStorageHostTest";
+
+    private static final String COMMON_CLASS =
+            "com.android.cts.externalstorageapp.CommonExternalStorageTest";
+
+    private static final String NONE_APK = "CtsExternalStorageApp.apk";
+    private static final String NONE_PKG = "com.android.cts.externalstorageapp";
+    private static final String NONE_CLASS = ".ExternalStorageTest";
+    private static final String READ_APK = "CtsReadExternalStorageApp.apk";
+    private static final String READ_PKG = "com.android.cts.readexternalstorageapp";
+    private static final String READ_CLASS = ".ReadExternalStorageTest";
+    private static final String WRITE_APK = "CtsWriteExternalStorageApp.apk";
+    private static final String WRITE_PKG = "com.android.cts.writeexternalstorageapp";
+    private static final String WRITE_CLASS = ".WriteExternalStorageTest";
+    private static final String MULTIUSER_APK = "CtsMultiUserStorageApp.apk";
+    private static final String MULTIUSER_PKG = "com.android.cts.multiuserstorageapp";
+    private static final String MULTIUSER_CLASS = ".MultiUserStorageTest";
+
+    private IAbi mAbi;
+    private IBuildInfo mCtsBuild;
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    private File getTestAppFile(String fileName) throws FileNotFoundException {
+        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        assertNotNull(mAbi);
+        assertNotNull(mCtsBuild);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Verify that app with no external storage permissions works correctly.
+     */
+    public void testExternalStorageNone() throws Exception {
+        final int[] users = createUsersForTest();
+        try {
+            wipePrimaryExternalStorage();
+
+            getDevice().uninstallPackage(NONE_PKG);
+            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
+
+            for (int user : users) {
+                runDeviceTests(NONE_PKG, COMMON_CLASS, user);
+                runDeviceTests(NONE_PKG, NONE_CLASS, user);
+            }
+        } finally {
+            getDevice().uninstallPackage(NONE_PKG);
+            removeUsersForTest(users);
+        }
+    }
+
+    /**
+     * Verify that app with
+     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} works
+     * correctly.
+     */
+    public void testExternalStorageRead() throws Exception {
+        final int[] users = createUsersForTest();
+        try {
+            wipePrimaryExternalStorage();
+
+            getDevice().uninstallPackage(READ_PKG);
+            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
+
+            for (int user : users) {
+                runDeviceTests(READ_PKG, COMMON_CLASS, user);
+                runDeviceTests(READ_PKG, READ_CLASS, user);
+            }
+        } finally {
+            getDevice().uninstallPackage(READ_PKG);
+            removeUsersForTest(users);
+        }
+    }
+
+    /**
+     * Verify that app with
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} works
+     * correctly.
+     */
+    public void testExternalStorageWrite() throws Exception {
+        final int[] users = createUsersForTest();
+        try {
+            wipePrimaryExternalStorage();
+
+            getDevice().uninstallPackage(WRITE_PKG);
+            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
+
+            for (int user : users) {
+                runDeviceTests(WRITE_PKG, COMMON_CLASS, user);
+                runDeviceTests(WRITE_PKG, WRITE_CLASS, user);
+            }
+        } finally {
+            getDevice().uninstallPackage(WRITE_PKG);
+            removeUsersForTest(users);
+        }
+    }
+
+    /**
+     * Verify that app with WRITE_EXTERNAL can leave gifts in external storage
+     * directories belonging to other apps, and those apps can read.
+     */
+    public void testExternalStorageGifts() throws Exception {
+        final int[] users = createUsersForTest();
+        try {
+            wipePrimaryExternalStorage();
+
+            getDevice().uninstallPackage(NONE_PKG);
+            getDevice().uninstallPackage(READ_PKG);
+            getDevice().uninstallPackage(WRITE_PKG);
+            final String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+
+            // We purposefully delay the installation of the reading apps to
+            // verify that the daemon correctly invalidates any caches.
+            assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
+            for (int user : users) {
+                runDeviceTests(WRITE_PKG, ".WriteGiftTest", user);
+            }
+
+            assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
+            assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
+            for (int user : users) {
+                runDeviceTests(READ_PKG, ".ReadGiftTest", user);
+                runDeviceTests(NONE_PKG, ".GiftTest", user);
+            }
+        } finally {
+            getDevice().uninstallPackage(NONE_PKG);
+            getDevice().uninstallPackage(READ_PKG);
+            getDevice().uninstallPackage(WRITE_PKG);
+            removeUsersForTest(users);
+        }
+    }
+
+    /**
+     * Test multi-user emulated storage environment, ensuring that each user has
+     * isolated storage.
+     */
+    public void testMultiUserStorageIsolated() throws Exception {
+        final int[] users = createUsersForTest();
+        try {
+            if (users.length == 1) {
+                Log.d(TAG, "Single user device; skipping isolated storage tests");
+                return;
+            }
+
+            final int owner = users[0];
+            final int secondary = users[1];
+
+            // Install our test app
+            getDevice().uninstallPackage(MULTIUSER_PKG);
+            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            final String installResult = getDevice()
+                    .installPackage(getTestAppFile(MULTIUSER_APK), false, options);
+            assertNull("Failed to install: " + installResult, installResult);
+
+            // Clear data from previous tests
+            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testCleanIsolatedStorage", owner);
+            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testCleanIsolatedStorage", secondary);
+
+            // Have both users try writing into isolated storage
+            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testWriteIsolatedStorage", owner);
+            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testWriteIsolatedStorage", secondary);
+
+            // Verify they both have isolated view of storage
+            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testReadIsolatedStorage", owner);
+            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testReadIsolatedStorage", secondary);
+
+            // Verify they can't poke at each other
+            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testUserIsolation", owner);
+            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testUserIsolation", secondary);
+        } finally {
+            getDevice().uninstallPackage(MULTIUSER_PKG);
+            removeUsersForTest(users);
+        }
+    }
+
+    private void wipePrimaryExternalStorage() throws DeviceNotAvailableException {
+        getDevice().executeShellCommand("rm -rf /sdcard/Android");
+        getDevice().executeShellCommand("rm -rf /sdcard/DCIM");
+        getDevice().executeShellCommand("rm -rf /sdcard/MUST_*");
+    }
+
+    private int[] createUsersForTest() throws DeviceNotAvailableException {
+        return Utils.createUsersForTest(getDevice());
+    }
+
+    private void removeUsersForTest(int[] users) throws DeviceNotAvailableException {
+        Utils.removeUsersForTest(getDevice(), users);
+    }
+
+    private void runDeviceTests(String packageName, String testClassName, int userId)
+            throws DeviceNotAvailableException {
+        Utils.runDeviceTests(getDevice(), packageName, testClassName, userId);
+    }
+
+    private void runDeviceTests(String packageName, String testClassName, String testMethodName,
+            int userId) throws DeviceNotAvailableException {
+        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName, userId);
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
new file mode 100644
index 0000000..53a54dd
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
@@ -0,0 +1,515 @@
+/*
+ * 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.appsecurity.cts;
+
+import com.android.cts.migration.MigrationHelper;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.ddmlib.testrunner.TestResult;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
+import com.android.ddmlib.testrunner.TestRunResult;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Map;
+
+/**
+ * Tests for Keyset based features.
+ */
+public class KeySetHostTest extends DeviceTestCase implements IBuildReceiver {
+
+    private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
+
+    /* package with device-side tests */
+    private static final String KEYSET_TEST_PKG = "com.android.cts.keysets.testapp";
+    private static final String KEYSET_TEST_APP_APK = "CtsKeySetTestApp.apk";
+
+    /* plain test apks with different signing and upgrade keysets */
+    private static final String KEYSET_PKG = "com.android.cts.keysets";
+    private static final String A_SIGNED_NO_UPGRADE =
+            "CtsKeySetSigningAUpgradeNone.apk";
+    private static final String A_SIGNED_A_UPGRADE =
+            "CtsKeySetSigningAUpgradeA.apk";
+    private static final String A_SIGNED_B_UPGRADE =
+            "CtsKeySetSigningAUpgradeB.apk";
+    private static final String A_SIGNED_A_OR_B_UPGRADE =
+            "CtsKeySetSigningAUpgradeAOrB.apk";
+    private static final String B_SIGNED_A_UPGRADE =
+            "CtsKeySetSigningBUpgradeA.apk";
+    private static final String B_SIGNED_B_UPGRADE =
+            "CtsKeySetSigningBUpgradeB.apk";
+    private static final String A_AND_B_SIGNED_A_UPGRADE =
+            "CtsKeySetSigningAAndBUpgradeA.apk";
+    private static final String A_AND_B_SIGNED_B_UPGRADE =
+            "CtsKeySetSigningAAndBUpgradeB.apk";
+    private static final String A_AND_C_SIGNED_B_UPGRADE =
+            "CtsKeySetSigningAAndCUpgradeB.apk";
+    private static final String SHARED_USR_A_SIGNED_B_UPGRADE =
+            "CtsKeySetSharedUserSigningAUpgradeB.apk";
+    private static final String SHARED_USR_B_SIGNED_B_UPGRADE =
+            "CtsKeySetSharedUserSigningBUpgradeB.apk";
+    private static final String A_SIGNED_BAD_B_B_UPGRADE =
+            "CtsKeySetSigningABadUpgradeB.apk";
+    private static final String C_SIGNED_BAD_A_AB_UPGRADE =
+            "CtsKeySetSigningCBadAUpgradeAB.apk";
+    private static final String A_SIGNED_NO_B_B_UPGRADE =
+            "CtsKeySetSigningANoDefUpgradeB.apk";
+    private static final String A_SIGNED_EC_A_UPGRADE =
+            "CtsKeySetSigningAUpgradeEcA.apk";
+    private static final String EC_A_SIGNED_A_UPGRADE =
+            "CtsKeySetSigningEcAUpgradeA.apk";
+
+    /* package which defines the KEYSET_PERM_NAME signature permission */
+    private static final String KEYSET_PERM_DEF_PKG =
+            "com.android.cts.keysets_permdef";
+
+    /* The apks defining and using the permission have both A and B as upgrade keys */
+    private static final String PERM_DEF_A_SIGNED =
+            "CtsKeySetPermDefSigningA.apk";
+    private static final String PERM_DEF_B_SIGNED =
+            "CtsKeySetPermDefSigningB.apk";
+    private static final String PERM_USE_A_SIGNED =
+            "CtsKeySetPermUseSigningA.apk";
+    private static final String PERM_USE_B_SIGNED =
+            "CtsKeySetPermUseSigningB.apk";
+
+    private static final String PERM_TEST_CLASS =
+        "com.android.cts.keysets.KeySetPermissionsTest";
+
+    private static final String LOG_TAG = "AppsecurityHostTests";
+
+    private File getTestAppFile(String fileName) throws FileNotFoundException {
+        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+    }
+
+    /**
+     * Helper method that checks that all tests in given result passed, and attempts to generate
+     * a meaningful error message if they failed.
+     *
+     * @param result
+     */
+    private void assertDeviceTestsPass(TestRunResult result) {
+        assertFalse(String.format("Failed to successfully run device tests for %s. Reason: %s",
+                result.getName(), result.getRunFailureMessage()), result.isRunFailure());
+
+        if (result.hasFailedTests()) {
+
+            /* build a meaningful error message */
+            StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
+            for (Map.Entry<TestIdentifier, TestResult> resultEntry :
+                result.getTestResults().entrySet()) {
+                if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
+                    errorBuilder.append(resultEntry.getKey().toString());
+                    errorBuilder.append(":\n");
+                    errorBuilder.append(resultEntry.getValue().getStackTrace());
+                }
+            }
+            fail(errorBuilder.toString());
+        }
+    }
+
+    /**
+     * Helper method that checks that all tests in given result passed, and attempts to generate
+     * a meaningful error message if they failed.
+     *
+     * @param result
+     */
+    private void assertDeviceTestsFail(String msg, TestRunResult result) {
+        assertFalse(String.format("Failed to successfully run device tests for %s. Reason: %s",
+                result.getName(), result.getRunFailureMessage()), result.isRunFailure());
+
+        if (!result.hasFailedTests()) {
+            fail(msg);
+        }
+    }
+
+    /**
+     * Helper method that will run the specified packages tests on device.
+     *
+     * @param pkgName Android application package for tests
+     * @return <code>true</code> if all tests passed.
+     * @throws DeviceNotAvailableException if connection to device was lost.
+     */
+    private boolean runDeviceTests(String pkgName) throws DeviceNotAvailableException {
+        return runDeviceTests(pkgName, null, null);
+    }
+
+    /**
+     * Helper method that will run the specified packages tests on device.
+     *
+     * @param pkgName Android application package for tests
+     * @return <code>true</code> if all tests passed.
+     * @throws DeviceNotAvailableException if connection to device was lost.
+     */
+    private boolean runDeviceTests(String pkgName, String testClassName, String testMethodName)
+            throws DeviceNotAvailableException {
+        TestRunResult runResult = doRunTests(pkgName, testClassName, testMethodName);
+        return !runResult.hasFailedTests();
+    }
+
+    /**
+     * Helper method to run tests and return the listener that collected the results.
+     *
+     * @param pkgName Android application package for tests
+     * @return the {@link TestRunResult}
+     * @throws DeviceNotAvailableException if connection to device was lost.
+     */
+    private TestRunResult doRunTests(String pkgName, String testClassName,
+            String testMethodName) throws DeviceNotAvailableException {
+
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(pkgName,
+                RUNNER, getDevice().getIDevice());
+        if (testClassName != null && testMethodName != null) {
+            testRunner.setMethodName(testClassName, testMethodName);
+        }
+        CollectingTestListener listener = new CollectingTestListener();
+        getDevice().runInstrumentationTests(testRunner, listener);
+        return listener.getCurrentRunResults();
+    }
+
+    /**
+     * Helper method which installs a package and an upgrade to it.
+     *
+     * @param pkgName - package name of apk.
+     * @param firstApk - first apk to install
+     * @param secondApk - apk to which we attempt to upgrade
+     * @param expectedResult - null if successful, otherwise expected error.
+     */
+    private String testPackageUpgrade(String pkgName, String firstApk,
+             String secondApk) throws Exception {
+        String installResult;
+        try {
+
+            /* cleanup test apps that might be installed from previous partial test run */
+            mDevice.uninstallPackage(pkgName);
+
+            installResult = mDevice.installPackage(getTestAppFile(firstApk),
+                    false);
+            /* we should always succeed on first-install */
+            assertNull(String.format("failed to install %s, Reason: %s", pkgName,
+                       installResult), installResult);
+
+            /* attempt to install upgrade */
+            installResult = mDevice.installPackage(getTestAppFile(secondApk),
+                    true);
+        } finally {
+            mDevice.uninstallPackage(pkgName);
+        }
+        return installResult;
+    }
+    /**
+     * A reference to the device under test.
+     */
+    private ITestDevice mDevice;
+
+    private IBuildInfo mCtsBuild;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    @Override
+        protected void setUp() throws Exception {
+        super.setUp();
+        mDevice = getDevice();
+        assertNotNull(mCtsBuild);
+    }
+
+    /**
+     * Tests for KeySet based key rotation
+     */
+
+    /*
+     * Check if an apk which does not specify an upgrade-key-set may be upgraded
+     * to an apk which does.
+     */
+    public void testNoKSToUpgradeKS() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_NO_UPGRADE, A_SIGNED_A_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from no specified upgrade-key-set"
+                + "to version with specified upgrade-key-set, Reason: %s", installResult),
+                installResult);
+    }
+
+    /*
+     * Check if an apk which does specify an upgrade-key-set may be upgraded
+     * to an apk which does not.
+     */
+    public void testUpgradeKSToNoKS() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE, A_SIGNED_NO_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from specified upgrade-key-set"
+                + "to version without specified upgrade-key-set, Reason: %s", installResult),
+                installResult);
+    }
+
+    /*
+     * Check if an apk signed by a key other than the upgrade keyset can update
+     * an app
+     */
+    public void testUpgradeKSWithWrongKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE, B_SIGNED_A_UPGRADE);
+        assertNotNull("upgrade to improperly signed app succeeded!", installResult);
+    }
+
+    /*
+     * Check if an apk signed by its signing key, which is not an upgrade key,
+     * can upgrade an app.
+     */
+    public void testUpgradeKSWithWrongSigningKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_B_UPGRADE, A_SIGNED_B_UPGRADE);
+         assertNotNull("upgrade to improperly signed app succeeded!",
+                 installResult);
+    }
+
+    /*
+     * Check if an apk signed by its upgrade key, which is not its signing key,
+     * can upgrade an app.
+     */
+    public void testUpgradeKSWithUpgradeKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_B_UPGRADE, B_SIGNED_B_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
+                 + "to version signed by upgrade-key-set key-b, Reason: %s", installResult),
+                 installResult);
+    }
+
+    /*
+     * Check if an apk signed by its upgrade key, which is its signing key, can
+     * upgrade an app.
+     */
+    public void testUpgradeKSWithSigningUpgradeKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE, A_SIGNED_A_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
+                    + "to version signed by upgrade-key-set key-b, Reason: %s", installResult),
+                    installResult);
+    }
+
+    /*
+     * Check if an apk signed by multiple keys, one of which is its upgrade key,
+     * can upgrade an app.
+     */
+    public void testMultipleUpgradeKSWithUpgradeKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE,
+                A_AND_B_SIGNED_A_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
+                + "to version signed by upgrade-key-set key-b, Reason: %s", installResult),
+                installResult);
+    }
+
+    /*
+     * Check if an apk signed by multiple keys, its signing keys,
+     * but none of which is an upgrade key, can upgrade an app.
+     */
+    public void testMultipleUpgradeKSWithSigningKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_AND_C_SIGNED_B_UPGRADE,
+                A_AND_C_SIGNED_B_UPGRADE);
+        assertNotNull("upgrade to improperly signed app succeeded!", installResult);
+    }
+
+    /*
+     * Check if an apk which defines multiple (two) upgrade keysets is
+     * upgrade-able by either.
+     */
+    public void testUpgradeKSWithMultipleUpgradeKeySetsFirstKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_OR_B_UPGRADE,
+                A_SIGNED_A_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
+                + "to one signed by first upgrade keyset key-a, Reason: %s", installResult),
+                installResult);
+        installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_OR_B_UPGRADE,
+                B_SIGNED_B_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
+                + "to one signed by second upgrade keyset key-b, Reason: %s", installResult),
+                installResult);
+    }
+
+    /**
+     * Helper method which installs a package defining a permission and a package
+     * using the permission, and then rotates the signing keys for one of them.
+     * A device-side test is then used to ascertain whether or not the permission
+     * was appropriately gained or lost.
+     *
+     * @param permDefApk - apk to install which defines the sig-permissoin
+     * @param permUseApk - apk to install which declares it uses the permission
+     * @param upgradeApk - apk to install which upgrades one of the first two
+     * @param hasPermBeforeUpgrade - whether we expect the consuming app to have
+     *        the permission before the upgrade takes place.
+     * @param hasPermAfterUpgrade - whether we expect the consuming app to have
+     *        the permission after the upgrade takes place.
+     */
+    private void testKeyRotationPerm(String permDefApk, String permUseApk,
+            String upgradeApk, boolean hasPermBeforeUpgrade,
+            boolean hasPermAfterUpgrade) throws Exception {
+        try {
+
+            /* cleanup test apps that might be installed from previous partial test run */
+            mDevice.uninstallPackage(KEYSET_PKG);
+            mDevice.uninstallPackage(KEYSET_PERM_DEF_PKG);
+            mDevice.uninstallPackage(KEYSET_TEST_PKG);
+
+            /* install PERM_DEF, KEYSET_APP and KEYSET_TEST_APP */
+            String installResult = mDevice.installPackage(
+                    getTestAppFile(permDefApk), false);
+            assertNull(String.format("failed to install keyset perm-def app, Reason: %s",
+                       installResult), installResult);
+            installResult = getDevice().installPackage(
+                    getTestAppFile(permUseApk), false);
+            assertNull(String.format("failed to install keyset test app. Reason: %s",
+                    installResult), installResult);
+            installResult = getDevice().installPackage(
+                    getTestAppFile(KEYSET_TEST_APP_APK), false);
+            assertNull(String.format("failed to install keyset test app. Reason: %s",
+                    installResult), installResult);
+
+            /* verify package does have perm */
+            TestRunResult result = doRunTests(KEYSET_TEST_PKG, PERM_TEST_CLASS,
+                    "testHasPerm");
+            if (hasPermBeforeUpgrade) {
+                assertDeviceTestsPass(result);
+            } else {
+                assertDeviceTestsFail(" has permission permission it should not have.", result);
+            }
+
+            /* rotate keys */
+            installResult = mDevice.installPackage(getTestAppFile(upgradeApk),
+                    true);
+            result = doRunTests(KEYSET_TEST_PKG, PERM_TEST_CLASS,
+                    "testHasPerm");
+            if (hasPermAfterUpgrade) {
+                assertDeviceTestsPass(result);
+            } else {
+                assertDeviceTestsFail(KEYSET_PKG + " has permission it should not have.", result);
+            }
+        } finally {
+            mDevice.uninstallPackage(KEYSET_PKG);
+            mDevice.uninstallPackage(KEYSET_PERM_DEF_PKG);
+            mDevice.uninstallPackage(KEYSET_TEST_PKG);
+        }
+    }
+
+    /*
+     * Check if an apk gains signature-level permission after changing to a new
+     * signature, for which a permission should be granted.
+     */
+    public void testUpgradeSigPermGained() throws Exception {
+        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_B_SIGNED, PERM_USE_A_SIGNED,
+                false, true);
+    }
+
+    /*
+     * Check if an apk loses signature-level permission after changing to a new
+     * signature, from one for which a permission was previously granted.
+     */
+    public void testUpgradeSigPermLost() throws Exception {
+        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_A_SIGNED, PERM_USE_B_SIGNED,
+                true, false);
+    }
+
+    /*
+     * Check if an apk gains signature-level permission after the app defining
+     * it rotates to the same signature.
+     */
+    public void testUpgradeDefinerSigPermGained() throws Exception {
+        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_B_SIGNED, PERM_DEF_B_SIGNED,
+                false, true);
+    }
+
+    /*
+     * Check if an apk loses signature-level permission after the app defining
+     * it rotates to a different signature.
+     */
+    public void testUpgradeDefinerSigPermLost() throws Exception {
+        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_A_SIGNED, PERM_DEF_B_SIGNED,
+                true, false);
+    }
+
+    /*
+     * Check if an apk which indicates it uses a sharedUserId and defines an
+     * upgrade keyset is allowed to rotate to that keyset.
+     */
+    public void testUpgradeSharedUser() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, SHARED_USR_A_SIGNED_B_UPGRADE,
+                SHARED_USR_B_SIGNED_B_UPGRADE);
+        assertNotNull("upgrade allowed for app with shareduserid!", installResult);
+    }
+
+    /*
+     * Check that an apk with an upgrade key represented by a bad public key
+     * fails to install.
+     */
+    public void testBadUpgradeBadPubKey() throws Exception {
+        mDevice.uninstallPackage(KEYSET_PKG);
+        String installResult = mDevice.installPackage(getTestAppFile(A_SIGNED_BAD_B_B_UPGRADE),
+                false);
+        assertNotNull("Installation of apk with upgrade key referring to a bad public key succeeded!",
+                installResult);
+    }
+
+    /*
+     * Check that an apk with an upgrade keyset that includes a bad public key fails to install.
+     */
+    public void testBadUpgradeMissingPubKey() throws Exception {
+        mDevice.uninstallPackage(KEYSET_PKG);
+        String installResult = mDevice.installPackage(getTestAppFile(C_SIGNED_BAD_A_AB_UPGRADE),
+                false);
+        assertNotNull("Installation of apk with upgrade key referring to a bad public key succeeded!",
+                installResult);
+    }
+
+    /*
+     * Check that an apk with an upgrade key that has no corresponding public key fails to install.
+     */
+    public void testBadUpgradeNoPubKey() throws Exception {
+        mDevice.uninstallPackage(KEYSET_PKG);
+        String installResult = mDevice.installPackage(getTestAppFile(A_SIGNED_NO_B_B_UPGRADE),
+                false);
+        assertNotNull("Installation of apk with upgrade key referring to a bad public key succeeded!",
+                installResult);
+    }
+
+    /*
+     * Check if an apk signed by RSA pub key can upgrade to apk signed by EC key.
+     */
+    public void testUpgradeKSRsaToEC() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_EC_A_UPGRADE,
+                EC_A_SIGNED_A_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by RSA key"
+                 + "to version signed by EC upgrade-key-set, Reason: %s", installResult),
+                 installResult);
+    }
+
+    /*
+     * Check if an apk signed by EC pub key can upgrade to apk signed by RSA key.
+     */
+    public void testUpgradeKSECToRSA() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, EC_A_SIGNED_A_UPGRADE,
+                A_SIGNED_EC_A_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by EC key"
+                 + "to version signed by RSA upgrade-key-set, Reason: %s", installResult),
+                 installResult);
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
new file mode 100644
index 0000000..6c5e4a5
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 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.appsecurity.cts;
+
+import com.android.cts.migration.MigrationHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+/**
+ * Set of tests that verify behavior of runtime permissions, including both
+ * dynamic granting and behavior of legacy apps.
+ */
+public class PermissionsHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+    private static final String PKG = "com.android.cts.usepermission";
+
+    private static final String APK = "CtsUsePermissionApp.apk";
+    private static final String APK_COMPAT = "CtsUsePermissionAppCompat.apk";
+
+    private IAbi mAbi;
+    private IBuildInfo mCtsBuild;
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        assertNotNull(mAbi);
+        assertNotNull(mCtsBuild);
+
+        getDevice().uninstallPackage(PKG);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        getDevice().uninstallPackage(PKG);
+    }
+
+    public void testFail() throws Exception {
+        // Sanity check that remote failure is host failure
+        assertNull(getDevice().installPackage(
+                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        try {
+            runDeviceTests(PKG, ".UsePermissionTest", "testFail");
+            fail("Expected remote failure");
+        } catch (AssertionError expected) {
+        }
+    }
+
+    public void testKill() throws Exception {
+        // Sanity check that remote kill is host failure
+        assertNull(getDevice().installPackage(
+                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        try {
+            runDeviceTests(PKG, ".UsePermissionTest", "testKill");
+            fail("Expected remote failure");
+        } catch (AssertionError expected) {
+        }
+    }
+
+    public void testDefault() throws Exception {
+        assertNull(getDevice().installPackage(
+                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        runDeviceTests(PKG, ".UsePermissionTest", "testDefault");
+    }
+
+    public void testGranted() throws Exception {
+        assertNull(getDevice().installPackage(
+                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        grantPermission(PKG, "android.permission.READ_EXTERNAL_STORAGE");
+        grantPermission(PKG, "android.permission.WRITE_EXTERNAL_STORAGE");
+        runDeviceTests(PKG, ".UsePermissionTest", "testGranted");
+    }
+
+    public void testInteractiveGrant() throws Exception {
+        assertNull(getDevice().installPackage(
+                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        runDeviceTests(PKG, ".UsePermissionTest", "testInteractiveGrant");
+    }
+
+    public void testRuntimeGroupGrantSpecificity() throws Exception {
+        assertNull(getDevice().installPackage(
+                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        runDeviceTests(PKG, ".UsePermissionTest", "testRuntimeGroupGrantSpecificity");
+    }
+
+    public void testRuntimeGroupGrantExpansion() throws Exception {
+        assertNull(getDevice().installPackage(
+                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        runDeviceTests(PKG, ".UsePermissionTest", "testRuntimeGroupGrantExpansion");
+    }
+
+    public void testCompatDefault() throws Exception {
+        assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, APK_COMPAT),
+                false, false));
+        runDeviceTests(PKG, ".UsePermissionCompatTest", "testCompatDefault");
+    }
+
+    public void testCompatRevoked() throws Exception {
+        assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, APK_COMPAT),
+                false, false));
+        setAppOps(PKG, "android:read_external_storage", "deny");
+        setAppOps(PKG, "android:write_external_storage", "deny");
+        runDeviceTests(PKG, ".UsePermissionCompatTest", "testCompatRevoked");
+    }
+
+    private void runDeviceTests(String packageName, String testClassName, String testMethodName)
+            throws DeviceNotAvailableException {
+        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
+    }
+
+    private void grantPermission(String pkg, String permission) throws Exception {
+        assertEmpty(getDevice().executeShellCommand("pm grant " + pkg + " " + permission));
+    }
+
+    private void revokePermission(String pkg, String permission) throws Exception {
+        assertEmpty(getDevice().executeShellCommand("pm revoke " + pkg + " " + permission));
+    }
+
+    private void setAppOps(String pkg, String op, String mode) throws Exception {
+        assertEmpty(getDevice().executeShellCommand("appops set " + pkg + " " + op + " " + mode));
+    }
+
+    private static void assertEmpty(String str) {
+        if (str == null || str.length() == 0) {
+            return;
+        } else {
+            fail("Expected empty string but found " + str);
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
new file mode 100644
index 0000000..a2ef1f3
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
@@ -0,0 +1,429 @@
+/*
+ * 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.appsecurity.cts;
+
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.cts.migration.MigrationHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Tests that verify installing of various split APKs from host side.
+ */
+public class SplitTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+    static final String PKG = "com.android.cts.splitapp";
+    static final String CLASS = ".SplitAppTest";
+
+    static final String APK = "CtsSplitApp.apk";
+
+    static final String APK_mdpi = "CtsSplitApp_mdpi-v4.apk";
+    static final String APK_hdpi = "CtsSplitApp_hdpi-v4.apk";
+    static final String APK_xhdpi = "CtsSplitApp_xhdpi-v4.apk";
+    static final String APK_xxhdpi = "CtsSplitApp_xxhdpi-v4.apk";
+
+    private static final String APK_v7 = "CtsSplitApp_v7.apk";
+    private static final String APK_fr = "CtsSplitApp_fr.apk";
+    private static final String APK_de = "CtsSplitApp_de.apk";
+
+    private static final String APK_x86 = "CtsSplitApp_x86.apk";
+    private static final String APK_x86_64 = "CtsSplitApp_x86_64.apk";
+    private static final String APK_armeabi_v7a = "CtsSplitApp_armeabi-v7a.apk";
+    private static final String APK_armeabi = "CtsSplitApp_armeabi.apk";
+    private static final String APK_arm64_v8a = "CtsSplitApp_arm64-v8a.apk";
+    private static final String APK_mips64 = "CtsSplitApp_mips64.apk";
+    private static final String APK_mips = "CtsSplitApp_mips.apk";
+
+    private static final String APK_DIFF_REVISION = "CtsSplitAppDiffRevision.apk";
+    private static final String APK_DIFF_REVISION_v7 = "CtsSplitAppDiffRevision_v7.apk";
+
+    private static final String APK_DIFF_VERSION = "CtsSplitAppDiffVersion.apk";
+    private static final String APK_DIFF_VERSION_v7 = "CtsSplitAppDiffVersion_v7.apk";
+
+    private static final String APK_DIFF_CERT = "CtsSplitAppDiffCert.apk";
+    private static final String APK_DIFF_CERT_v7 = "CtsSplitAppDiffCert_v7.apk";
+
+    private static final String APK_FEATURE = "CtsSplitAppFeature.apk";
+    private static final String APK_FEATURE_v7 = "CtsSplitAppFeature_v7.apk";
+
+    static final HashMap<String, String> ABI_TO_APK = new HashMap<>();
+
+    static {
+        ABI_TO_APK.put("x86", APK_x86);
+        ABI_TO_APK.put("x86_64", APK_x86_64);
+        ABI_TO_APK.put("armeabi-v7a", APK_armeabi_v7a);
+        ABI_TO_APK.put("armeabi", APK_armeabi);
+        ABI_TO_APK.put("arm64-v8a", APK_arm64_v8a);
+        ABI_TO_APK.put("mips64", APK_mips64);
+        ABI_TO_APK.put("mips", APK_mips);
+    }
+
+    private IAbi mAbi;
+    private IBuildInfo mCtsBuild;
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        assertNotNull(mAbi);
+        assertNotNull(mCtsBuild);
+
+        getDevice().uninstallPackage(PKG);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        getDevice().uninstallPackage(PKG);
+    }
+
+    public void testSingleBase() throws Exception {
+        new InstallMultiple().addApk(APK).run();
+        runDeviceTests(PKG, CLASS, "testSingleBase");
+    }
+
+    public void testDensitySingle() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_mdpi).run();
+        runDeviceTests(PKG, CLASS, "testDensitySingle");
+    }
+
+    public void testDensityAll() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_mdpi).addApk(APK_hdpi).addApk(APK_xhdpi)
+                .addApk(APK_xxhdpi).run();
+        runDeviceTests(PKG, CLASS, "testDensityAll");
+    }
+
+    /**
+     * Install first with low-resolution resources, then add a split that offers
+     * higher-resolution resources.
+     */
+    public void testDensityBest() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_mdpi).run();
+        runDeviceTests(PKG, CLASS, "testDensityBest1");
+
+        // Now splice in an additional split which offers better resources
+        new InstallMultiple().inheritFrom(PKG).addApk(APK_xxhdpi).run();
+        runDeviceTests(PKG, CLASS, "testDensityBest2");
+    }
+
+    /**
+     * Verify that an API-based split can change enabled/disabled state of
+     * manifest elements.
+     */
+    public void testApi() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_v7).run();
+        runDeviceTests(PKG, CLASS, "testApi");
+    }
+
+    public void testLocale() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_de).addApk(APK_fr).run();
+        runDeviceTests(PKG, CLASS, "testLocale");
+    }
+
+    /**
+     * Install test app with <em>single</em> split that exactly matches the
+     * currently active ABI. This also explicitly forces ABI when installing.
+     */
+    public void testNativeSingle() throws Exception {
+        final String abi = mAbi.getName();
+        final String apk = ABI_TO_APK.get(abi);
+        assertNotNull("Failed to find APK for ABI " + abi, apk);
+
+        new InstallMultiple().addApk(APK).addApk(apk).run();
+        runDeviceTests(PKG, CLASS, "testNative");
+    }
+
+    /**
+     * Install test app with <em>single</em> split that exactly matches the
+     * currently active ABI. This variant <em>does not</em> force the ABI when
+     * installing, instead exercising the system's ability to choose the ABI
+     * through inspection of the installed app.
+     */
+    public void testNativeSingleNatural() throws Exception {
+        final String abi = mAbi.getName();
+        final String apk = ABI_TO_APK.get(abi);
+        assertNotNull("Failed to find APK for ABI " + abi, apk);
+
+        new InstallMultiple().useNaturalAbi().addApk(APK).addApk(apk).run();
+        runDeviceTests(PKG, CLASS, "testNative");
+    }
+
+    /**
+     * Install test app with <em>all</em> possible ABI splits. This also
+     * explicitly forces ABI when installing.
+     */
+    public void testNativeAll() throws Exception {
+        final InstallMultiple inst = new InstallMultiple().addApk(APK);
+        for (String apk : ABI_TO_APK.values()) {
+            inst.addApk(apk);
+        }
+        inst.run();
+        runDeviceTests(PKG, CLASS, "testNative");
+    }
+
+    /**
+     * Install test app with <em>all</em> possible ABI splits. This variant
+     * <em>does not</em> force the ABI when installing, instead exercising the
+     * system's ability to choose the ABI through inspection of the installed
+     * app.
+     */
+    public void testNativeAllNatural() throws Exception {
+        final InstallMultiple inst = new InstallMultiple().useNaturalAbi().addApk(APK);
+        for (String apk : ABI_TO_APK.values()) {
+            inst.addApk(apk);
+        }
+        inst.run();
+        runDeviceTests(PKG, CLASS, "testNative");
+    }
+
+    public void testDuplicateBase() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK).runExpectingFailure();
+    }
+
+    public void testDuplicateSplit() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_v7).addApk(APK_v7).runExpectingFailure();
+    }
+
+    public void testDiffCert() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_DIFF_CERT_v7).runExpectingFailure();
+    }
+
+    public void testDiffCertInherit() throws Exception {
+        new InstallMultiple().addApk(APK).run();
+        new InstallMultiple().inheritFrom(PKG).addApk(APK_DIFF_CERT_v7).runExpectingFailure();
+    }
+
+    public void testDiffVersion() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_DIFF_VERSION_v7).runExpectingFailure();
+    }
+
+    public void testDiffVersionInherit() throws Exception {
+        new InstallMultiple().addApk(APK).run();
+        new InstallMultiple().inheritFrom(PKG).addApk(APK_DIFF_VERSION_v7).runExpectingFailure();
+    }
+
+    public void testDiffRevision() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_DIFF_REVISION_v7).run();
+        runDeviceTests(PKG, CLASS, "testRevision0_12");
+    }
+
+    public void testDiffRevisionInheritBase() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_v7).run();
+        runDeviceTests(PKG, CLASS, "testRevision0_0");
+        new InstallMultiple().inheritFrom(PKG).addApk(APK_DIFF_REVISION_v7).run();
+        runDeviceTests(PKG, CLASS, "testRevision0_12");
+    }
+
+    public void testDiffRevisionInheritSplit() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_v7).run();
+        runDeviceTests(PKG, CLASS, "testRevision0_0");
+        new InstallMultiple().inheritFrom(PKG).addApk(APK_DIFF_REVISION).run();
+        runDeviceTests(PKG, CLASS, "testRevision12_0");
+    }
+
+    public void testDiffRevisionDowngrade() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_DIFF_REVISION_v7).run();
+        new InstallMultiple().inheritFrom(PKG).addApk(APK_v7).runExpectingFailure();
+    }
+
+    public void testFeatureBase() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_FEATURE).run();
+        runDeviceTests(PKG, CLASS, "testFeatureBase");
+    }
+
+    public void testFeatureApi() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_FEATURE).addApk(APK_FEATURE_v7).run();
+        runDeviceTests(PKG, CLASS, "testFeatureApi");
+    }
+
+    public void testInheritUpdatedBase() throws Exception {
+        // TODO: flesh out this test
+    }
+
+    public void testInheritUpdatedSplit() throws Exception {
+        // TODO: flesh out this test
+    }
+
+    /**
+     * Verify that installing a new version of app wipes code cache.
+     */
+    public void testClearCodeCache() throws Exception {
+        new InstallMultiple().addApk(APK).run();
+        runDeviceTests(PKG, CLASS, "testCodeCacheWrite");
+        new InstallMultiple().addArg("-r").addApk(APK_DIFF_VERSION).run();
+        runDeviceTests(PKG, CLASS, "testCodeCacheRead");
+    }
+
+    private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+        public InstallMultiple() {
+            super(getDevice(), mCtsBuild, mAbi);
+        }
+    }
+
+    public static class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
+        private final ITestDevice mDevice;
+        private final IBuildInfo mBuild;
+        private final IAbi mAbi;
+
+        private final List<String> mArgs = new ArrayList<>();
+        private final List<File> mApks = new ArrayList<>();
+        private boolean mUseNaturalAbi;
+
+        public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) {
+            mDevice = device;
+            mBuild = buildInfo;
+            mAbi = abi;
+            addArg("-g");
+        }
+
+        T addArg(String arg) {
+            mArgs.add(arg);
+            return (T) this;
+        }
+
+        T addApk(String apk) throws FileNotFoundException {
+            mApks.add(MigrationHelper.getTestFile(mBuild, apk));
+            return (T) this;
+        }
+
+        T inheritFrom(String packageName) {
+            addArg("-r");
+            addArg("-p " + packageName);
+            return (T) this;
+        }
+
+        T useNaturalAbi() {
+            mUseNaturalAbi = true;
+            return (T) this;
+        }
+
+        T locationAuto() {
+            addArg("--install-location 0");
+            return (T) this;
+        }
+
+        T locationInternalOnly() {
+            addArg("--install-location 1");
+            return (T) this;
+        }
+
+        T locationPreferExternal() {
+            addArg("--install-location 2");
+            return (T) this;
+        }
+
+        T forceUuid(String uuid) {
+            addArg("--force-uuid " + uuid);
+            return (T) this;
+        }
+
+        void run() throws DeviceNotAvailableException {
+            run(true);
+        }
+
+        void runExpectingFailure() throws DeviceNotAvailableException {
+            run(false);
+        }
+
+        private void run(boolean expectingSuccess) throws DeviceNotAvailableException {
+            final ITestDevice device = mDevice;
+
+            // Create an install session
+            final StringBuilder cmd = new StringBuilder();
+            cmd.append("pm install-create");
+            for (String arg : mArgs) {
+                cmd.append(' ').append(arg);
+            }
+            if (!mUseNaturalAbi) {
+                cmd.append(' ').append(AbiUtils.createAbiFlag(mAbi.getName()));
+            }
+
+            String result = device.executeShellCommand(cmd.toString());
+            assertTrue(result, result.startsWith("Success"));
+
+            final int start = result.lastIndexOf("[");
+            final int end = result.lastIndexOf("]");
+            int sessionId = -1;
+            try {
+                if (start != -1 && end != -1 && start < end) {
+                    sessionId = Integer.parseInt(result.substring(start + 1, end));
+                }
+            } catch (NumberFormatException e) {
+            }
+            if (sessionId == -1) {
+                throw new IllegalStateException("Failed to create install session: " + result);
+            }
+
+            // Push our files into session. Ideally we'd use stdin streaming,
+            // but ddmlib doesn't support it yet.
+            for (int i = 0; i < mApks.size(); i++) {
+                final File apk = mApks.get(i);
+                final String remotePath = "/data/local/tmp/" + i + "_" + apk.getName();
+                if (!device.pushFile(apk, remotePath)) {
+                    throw new IllegalStateException("Failed to push " + apk);
+                }
+
+                cmd.setLength(0);
+                cmd.append("pm install-write");
+                cmd.append(' ').append(sessionId);
+                cmd.append(' ').append(i + "_" + apk.getName());
+                cmd.append(' ').append(remotePath);
+
+                result = device.executeShellCommand(cmd.toString());
+                assertTrue(result, result.startsWith("Success"));
+            }
+
+            // Everything staged; let's pull trigger
+            cmd.setLength(0);
+            cmd.append("pm install-commit");
+            cmd.append(' ').append(sessionId);
+
+            result = device.executeShellCommand(cmd.toString());
+            if (expectingSuccess) {
+                assertTrue(result, result.startsWith("Success"));
+            } else {
+                assertFalse(result, result.startsWith("Success"));
+            }
+        }
+    }
+
+    public void runDeviceTests(String packageName, String testClassName, String testMethodName)
+            throws DeviceNotAvailableException {
+        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
new file mode 100644
index 0000000..7048074
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
@@ -0,0 +1,165 @@
+/*
+ * 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.appsecurity.cts;
+
+import com.android.ddmlib.Log;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.ddmlib.testrunner.TestResult;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
+import com.android.ddmlib.testrunner.TestRunResult;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.CollectingTestListener;
+
+import java.util.Map;
+
+public class Utils {
+    private static final String TAG = "AppSecurity";
+
+    public static final int USER_OWNER = 0;
+
+    public static void runDeviceTests(ITestDevice device, String packageName)
+            throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, null, null, USER_OWNER);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, int userId)
+            throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, null, null, userId);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName)
+            throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, testClassName, null, USER_OWNER);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            int userId) throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, testClassName, null, userId);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName) throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, testClassName, testMethodName, USER_OWNER);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName, int userId) throws DeviceNotAvailableException {
+        if (testClassName != null && testClassName.startsWith(".")) {
+            testClassName = packageName + testClassName;
+        }
+
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName,
+                "android.support.test.runner.AndroidJUnitRunner", device.getIDevice());
+        if (testClassName != null && testMethodName != null) {
+            testRunner.setMethodName(testClassName, testMethodName);
+        } else if (testClassName != null) {
+            testRunner.setClassName(testClassName);
+        }
+
+        if (userId != USER_OWNER) {
+            // TODO: move this to RemoteAndroidTestRunner once it supports users
+            testRunner.addInstrumentationArg("hack_key", "hack_value --user " + userId);
+        }
+
+        final CollectingTestListener listener = new CollectingTestListener();
+        device.runInstrumentationTests(testRunner, listener);
+
+        final TestRunResult result = listener.getCurrentRunResults();
+        if (result.isRunFailure()) {
+            throw new AssertionError("Failed to successfully run device tests for "
+                    + result.getName() + ": " + result.getRunFailureMessage());
+        }
+
+        if (result.hasFailedTests()) {
+            // build a meaningful error message
+            StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
+            for (Map.Entry<TestIdentifier, TestResult> resultEntry :
+                result.getTestResults().entrySet()) {
+                if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
+                    errorBuilder.append(resultEntry.getKey().toString());
+                    errorBuilder.append(":\n");
+                    errorBuilder.append(resultEntry.getValue().getStackTrace());
+                }
+            }
+            throw new AssertionError(errorBuilder.toString());
+        }
+    }
+
+    private static boolean isMultiUserSupportedOnDevice(ITestDevice device)
+            throws DeviceNotAvailableException {
+        // TODO: move this to ITestDevice once it supports users
+        final String output = device.executeShellCommand("pm get-max-users");
+        try {
+            return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim()) > 1;
+        } catch (NumberFormatException e) {
+            throw new AssertionError("Failed to parse result: " + output);
+        }
+    }
+
+    /**
+     * Return set of users that test should be run for, creating a secondary
+     * user if the device supports it. Always call
+     * {@link #removeUsersForTest(ITestDevice, int[])} when finished.
+     */
+    public static int[] createUsersForTest(ITestDevice device) throws DeviceNotAvailableException {
+        if (isMultiUserSupportedOnDevice(device)) {
+            return new int[] { USER_OWNER, createUserOnDevice(device) };
+        } else {
+            Log.d(TAG, "Single user device; skipping isolated storage tests");
+            return new int[] { USER_OWNER };
+        }
+    }
+
+    public static void removeUsersForTest(ITestDevice device, int[] users)
+            throws DeviceNotAvailableException {
+        for (int user : users) {
+            if (user != USER_OWNER) {
+                removeUserOnDevice(device, user);
+            }
+        }
+    }
+
+    private static int createUserOnDevice(ITestDevice device) throws DeviceNotAvailableException {
+        // TODO: move this to ITestDevice once it supports users
+        final String name = "CTS_" + System.currentTimeMillis();
+        final String output = device.executeShellCommand("pm create-user " + name);
+        if (output.startsWith("Success")) {
+            try {
+                final int userId = Integer.parseInt(
+                        output.substring(output.lastIndexOf(" ")).trim());
+                device.executeShellCommand("am start-user " + userId);
+                return userId;
+            } catch (NumberFormatException e) {
+                throw new AssertionError("Failed to parse result: " + output);
+            }
+        } else {
+            throw new AssertionError("Failed to create user: " + output);
+        }
+    }
+
+    private static void removeUserOnDevice(ITestDevice device, int userId)
+            throws DeviceNotAvailableException {
+        // TODO: move this to ITestDevice once it supports users
+        final String output = device.executeShellCommand("pm remove-user " + userId);
+        if (output.startsWith("Error")) {
+            throw new AssertionError("Failed to remove user: " + output);
+        }
+    }
+
+}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
deleted file mode 100644
index 2ae2e10..0000000
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (C) 2015 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.appsecurity;
-
-import static com.android.cts.appsecurity.SplitTests.ABI_TO_APK;
-import static com.android.cts.appsecurity.SplitTests.APK;
-import static com.android.cts.appsecurity.SplitTests.APK_mdpi;
-import static com.android.cts.appsecurity.SplitTests.APK_xxhdpi;
-import static com.android.cts.appsecurity.SplitTests.CLASS;
-import static com.android.cts.appsecurity.SplitTests.PKG;
-
-import com.android.cts.appsecurity.SplitTests.BaseInstallMultiple;
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import java.util.Arrays;
-
-/**
- * Set of tests that verify behavior of adopted storage media, if supported.
- */
-public class AdoptableHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
-    private IAbi mAbi;
-    private CtsBuildHelper mCtsBuild;
-
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
-
-        getDevice().uninstallPackage(PKG);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-
-        getDevice().uninstallPackage(PKG);
-    }
-
-    public void testApps() throws Exception {
-        if (!hasAdoptable()) return;
-        final String diskId = getAdoptionDisk();
-        try {
-            final String abi = mAbi.getName();
-            final String apk = ABI_TO_APK.get(abi);
-            assertNotNull("Failed to find APK for ABI " + abi, apk);
-
-            // Install simple app on internal
-            new InstallMultiple().useNaturalAbi().addApk(APK).addApk(apk).run();
-            runDeviceTests(PKG, CLASS, "testDataInternal");
-            runDeviceTests(PKG, CLASS, "testDataWrite");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-            runDeviceTests(PKG, CLASS, "testNative");
-
-            // Adopt that disk!
-            assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
-            final LocalVolumeInfo vol = getAdoptionVolume();
-
-            // Move app and verify
-            assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " " + vol.uuid));
-            runDeviceTests(PKG, CLASS, "testDataNotInternal");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-            runDeviceTests(PKG, CLASS, "testNative");
-
-            // Unmount, remount and verify
-            getDevice().executeShellCommand("sm unmount " + vol.volId);
-            getDevice().executeShellCommand("sm mount " + vol.volId);
-            runDeviceTests(PKG, CLASS, "testDataNotInternal");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-            runDeviceTests(PKG, CLASS, "testNative");
-
-            // Move app back and verify
-            assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " internal"));
-            runDeviceTests(PKG, CLASS, "testDataInternal");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-            runDeviceTests(PKG, CLASS, "testNative");
-
-            // Un-adopt volume and app should still be fine
-            getDevice().executeShellCommand("sm partition " + diskId + " public");
-            runDeviceTests(PKG, CLASS, "testDataInternal");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-            runDeviceTests(PKG, CLASS, "testNative");
-
-        } finally {
-            cleanUp(diskId);
-        }
-    }
-
-    public void testPrimaryStorage() throws Exception {
-        if (!hasAdoptable()) return;
-        final String diskId = getAdoptionDisk();
-        try {
-            final String originalVol = getDevice()
-                    .executeShellCommand("sm get-primary-storage-uuid").trim();
-
-            if ("null".equals(originalVol)) {
-                verifyPrimaryInternal(diskId);
-            } else if ("primary_physical".equals(originalVol)) {
-                verifyPrimaryPhysical(diskId);
-            }
-        } finally {
-            cleanUp(diskId);
-        }
-    }
-
-    private void verifyPrimaryInternal(String diskId) throws Exception {
-        // Write some data to shared storage
-        new InstallMultiple().addApk(APK).run();
-        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
-        runDeviceTests(PKG, CLASS, "testPrimaryInternal");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataWrite");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
-
-        // Adopt that disk!
-        assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
-        final LocalVolumeInfo vol = getAdoptionVolume();
-
-        // Move storage there and verify that data went along for ride
-        assertSuccess(getDevice().executeShellCommand("pm move-primary-storage " + vol.uuid));
-        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
-
-        // Unmount and verify
-        getDevice().executeShellCommand("sm unmount " + vol.volId);
-        runDeviceTests(PKG, CLASS, "testPrimaryUnmounted");
-        getDevice().executeShellCommand("sm mount " + vol.volId);
-        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
-
-        // Move app and verify backing storage volume is same
-        assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " " + vol.uuid));
-        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
-
-        // And move back to internal
-        assertSuccess(getDevice().executeShellCommand("pm move-primary-storage internal"));
-        runDeviceTests(PKG, CLASS, "testPrimaryInternal");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
-
-        assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " internal"));
-        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
-    }
-
-    private void verifyPrimaryPhysical(String diskId) throws Exception {
-        // Write some data to shared storage
-        new InstallMultiple().addApk(APK).run();
-        runDeviceTests(PKG, CLASS, "testPrimaryPhysical");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataWrite");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
-
-        // Adopt that disk!
-        assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
-        final LocalVolumeInfo vol = getAdoptionVolume();
-
-        // Move primary storage there, but since we just nuked primary physical
-        // the storage device will be empty
-        assertSuccess(getDevice().executeShellCommand("pm move-primary-storage " + vol.uuid));
-        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataWrite");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
-
-        // Unmount and verify
-        getDevice().executeShellCommand("sm unmount " + vol.volId);
-        runDeviceTests(PKG, CLASS, "testPrimaryUnmounted");
-        getDevice().executeShellCommand("sm mount " + vol.volId);
-        runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
-
-        // And move to internal
-        assertSuccess(getDevice().executeShellCommand("pm move-primary-storage internal"));
-        runDeviceTests(PKG, CLASS, "testPrimaryOnSameVolume");
-        runDeviceTests(PKG, CLASS, "testPrimaryInternal");
-        runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
-    }
-
-    /**
-     * Verify that we can install both new and inherited packages directly on
-     * adopted volumes.
-     */
-    public void testPackageInstaller() throws Exception {
-        if (!hasAdoptable()) return;
-        final String diskId = getAdoptionDisk();
-        try {
-            assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
-            final LocalVolumeInfo vol = getAdoptionVolume();
-
-            // Install directly onto adopted volume
-            new InstallMultiple().locationAuto().forceUuid(vol.uuid)
-                    .addApk(APK).addApk(APK_mdpi).run();
-            runDeviceTests(PKG, CLASS, "testDataNotInternal");
-            runDeviceTests(PKG, CLASS, "testDensityBest1");
-
-            // Now splice in an additional split which offers better resources
-            new InstallMultiple().locationAuto().inheritFrom(PKG)
-                    .addApk(APK_xxhdpi).run();
-            runDeviceTests(PKG, CLASS, "testDataNotInternal");
-            runDeviceTests(PKG, CLASS, "testDensityBest2");
-
-        } finally {
-            cleanUp(diskId);
-        }
-    }
-
-    /**
-     * Verify behavior when changes occur while adopted device is ejected and
-     * returned at a later time.
-     */
-    public void testEjected() throws Exception {
-        if (!hasAdoptable()) return;
-        final String diskId = getAdoptionDisk();
-        try {
-            assertEmpty(getDevice().executeShellCommand("sm partition " + diskId + " private"));
-            final LocalVolumeInfo vol = getAdoptionVolume();
-
-            // Install directly onto adopted volume, and write data there
-            new InstallMultiple().locationAuto().forceUuid(vol.uuid).addApk(APK).run();
-            runDeviceTests(PKG, CLASS, "testDataNotInternal");
-            runDeviceTests(PKG, CLASS, "testDataWrite");
-            runDeviceTests(PKG, CLASS, "testDataRead");
-
-            // Now unmount and uninstall; leaving stale package on adopted volume
-            getDevice().executeShellCommand("sm unmount " + vol.volId);
-            getDevice().uninstallPackage(PKG);
-
-            // Install second copy on internal, but don't write anything
-            new InstallMultiple().locationInternalOnly().addApk(APK).run();
-            runDeviceTests(PKG, CLASS, "testDataInternal");
-
-            // Kick through a remount cycle, which should purge the adopted app
-            getDevice().executeShellCommand("sm mount " + vol.volId);
-            runDeviceTests(PKG, CLASS, "testDataInternal");
-            try {
-                runDeviceTests(PKG, CLASS, "testDataRead");
-                fail("Unexpected data from adopted volume picked up");
-            } catch (AssertionError expected) {
-            }
-            getDevice().executeShellCommand("sm unmount " + vol.volId);
-
-            // Uninstall the internal copy and remount; we should have no record of app
-            getDevice().uninstallPackage(PKG);
-            getDevice().executeShellCommand("sm mount " + vol.volId);
-
-            assertEmpty(getDevice().executeShellCommand("pm list packages " + PKG));
-        } finally {
-            cleanUp(diskId);
-        }
-    }
-
-    private boolean hasAdoptable() throws Exception {
-        return Boolean.parseBoolean(getDevice().executeShellCommand("sm has-adoptable").trim());
-    }
-
-    private String getAdoptionDisk() throws Exception {
-        final String disks = getDevice().executeShellCommand("sm list-disks adoptable");
-        if (disks == null || disks.length() == 0) {
-            throw new AssertionError("Devices that claim to support adoptable storage must have "
-                    + "adoptable media inserted during CTS to verify correct behavior");
-        }
-        return disks.split("\n")[0].trim();
-    }
-
-    private LocalVolumeInfo getAdoptionVolume() throws Exception {
-        String[] lines = null;
-        int attempt = 0;
-        while (attempt++ < 15) {
-            lines = getDevice().executeShellCommand("sm list-volumes private").split("\n");
-            for (String line : lines) {
-                final LocalVolumeInfo info = new LocalVolumeInfo(line.trim());
-                if (!"private".equals(info.volId) && "mounted".equals(info.state)) {
-                    return info;
-                }
-            }
-            Thread.sleep(1000);
-        }
-        throw new AssertionError("Expected private volume; found " + Arrays.toString(lines));
-    }
-
-    private void cleanUp(String diskId) throws Exception {
-        getDevice().executeShellCommand("sm partition " + diskId + " public");
-        getDevice().executeShellCommand("sm forget all");
-    }
-
-    private void runDeviceTests(String packageName, String testClassName, String testMethodName)
-            throws DeviceNotAvailableException {
-        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
-    }
-
-    private static void assertSuccess(String str) {
-        if (str == null || !str.startsWith("Success")) {
-            throw new AssertionError("Expected success string but found " + str);
-        }
-    }
-
-    private static void assertEmpty(String str) {
-        if (str != null && str.trim().length() > 0) {
-            throw new AssertionError("Expected empty string but found " + str);
-        }
-    }
-
-    private static class LocalVolumeInfo {
-        public String volId;
-        public String state;
-        public String uuid;
-
-        public LocalVolumeInfo(String line) {
-            final String[] split = line.split(" ");
-            volId = split[0];
-            state = split[1];
-            uuid = split[2];
-        }
-    }
-
-    private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
-        public InstallMultiple() {
-            super(getDevice(), mCtsBuild, mAbi);
-        }
-    }
-}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
deleted file mode 100644
index bf9e81c..0000000
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2009 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.appsecurity;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
-import com.android.ddmlib.Log;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-
-/**
- * Set of tests that verify various security checks involving multiple apps are
- * properly enforced.
- */
-public class AppSecurityTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
-
-    // testSharedUidDifferentCerts constants
-    private static final String SHARED_UI_APK = "CtsSharedUidInstall.apk";
-    private static final String SHARED_UI_PKG = "com.android.cts.shareuidinstall";
-    private static final String SHARED_UI_DIFF_CERT_APK = "CtsSharedUidInstallDiffCert.apk";
-    private static final String SHARED_UI_DIFF_CERT_PKG =
-        "com.android.cts.shareuidinstalldiffcert";
-
-    // testAppUpgradeDifferentCerts constants
-    private static final String SIMPLE_APP_APK = "CtsSimpleAppInstall.apk";
-    private static final String SIMPLE_APP_PKG = "com.android.cts.simpleappinstall";
-    private static final String SIMPLE_APP_DIFF_CERT_APK = "CtsSimpleAppInstallDiffCert.apk";
-
-    // testAppFailAccessPrivateData constants
-    private static final String APP_WITH_DATA_APK = "CtsAppWithData.apk";
-    private static final String APP_WITH_DATA_PKG = "com.android.cts.appwithdata";
-    private static final String APP_WITH_DATA_CLASS =
-            "com.android.cts.appwithdata.CreatePrivateDataTest";
-    private static final String APP_WITH_DATA_CREATE_METHOD =
-            "testCreatePrivateData";
-    private static final String APP_WITH_DATA_CHECK_NOEXIST_METHOD =
-            "testEnsurePrivateDataNotExist";
-    private static final String APP_ACCESS_DATA_APK = "CtsAppAccessData.apk";
-    private static final String APP_ACCESS_DATA_PKG = "com.android.cts.appaccessdata";
-
-    // testInstrumentationDiffCert constants
-    private static final String TARGET_INSTRUMENT_APK = "CtsTargetInstrumentationApp.apk";
-    private static final String TARGET_INSTRUMENT_PKG = "com.android.cts.targetinstrumentationapp";
-    private static final String INSTRUMENT_DIFF_CERT_APK = "CtsInstrumentationAppDiffCert.apk";
-    private static final String INSTRUMENT_DIFF_CERT_PKG =
-        "com.android.cts.instrumentationdiffcertapp";
-
-    // testPermissionDiffCert constants
-    private static final String DECLARE_PERMISSION_APK = "CtsPermissionDeclareApp.apk";
-    private static final String DECLARE_PERMISSION_PKG = "com.android.cts.permissiondeclareapp";
-    private static final String DECLARE_PERMISSION_COMPAT_APK = "CtsPermissionDeclareAppCompat.apk";
-    private static final String DECLARE_PERMISSION_COMPAT_PKG = "com.android.cts.permissiondeclareappcompat";
-
-    private static final String PERMISSION_DIFF_CERT_APK = "CtsUsePermissionDiffCert.apk";
-    private static final String PERMISSION_DIFF_CERT_PKG =
-        "com.android.cts.usespermissiondiffcertapp";
-
-    private static final String LOG_TAG = "AppSecurityTests";
-
-    private IAbi mAbi;
-    private CtsBuildHelper mCtsBuild;
-
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return mCtsBuild.getTestApp(fileName);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // ensure build has been set before test is run
-        assertNotNull(mCtsBuild);
-    }
-
-    /**
-     * Test that an app that declares the same shared uid as an existing app, cannot be installed
-     * if it is signed with a different certificate.
-     */
-    public void testSharedUidDifferentCerts() throws Exception {
-        Log.i(LOG_TAG, "installing apks with shared uid, but different certs");
-        try {
-            // cleanup test apps that might be installed from previous partial test run
-            getDevice().uninstallPackage(SHARED_UI_PKG);
-            getDevice().uninstallPackage(SHARED_UI_DIFF_CERT_PKG);
-
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            String installResult = getDevice().installPackage(getTestAppFile(SHARED_UI_APK),
-                    false, options);
-            assertNull(String.format("failed to install shared uid app, Reason: %s", installResult),
-                    installResult);
-            installResult = getDevice().installPackage(getTestAppFile(SHARED_UI_DIFF_CERT_APK),
-                    false, options);
-            assertNotNull("shared uid app with different cert than existing app installed " +
-                    "successfully", installResult);
-            assertEquals("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE", installResult);
-        } finally {
-            getDevice().uninstallPackage(SHARED_UI_PKG);
-            getDevice().uninstallPackage(SHARED_UI_DIFF_CERT_PKG);
-        }
-    }
-
-    /**
-     * Test that an app update cannot be installed over an existing app if it has a different
-     * certificate.
-     */
-    public void testAppUpgradeDifferentCerts() throws Exception {
-        Log.i(LOG_TAG, "installing app upgrade with different certs");
-        try {
-            // cleanup test app that might be installed from previous partial test run
-            getDevice().uninstallPackage(SIMPLE_APP_PKG);
-
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            String installResult = getDevice().installPackage(getTestAppFile(SIMPLE_APP_APK),
-                    false, options);
-            assertNull(String.format("failed to install simple app. Reason: %s", installResult),
-                    installResult);
-            installResult = getDevice().installPackage(getTestAppFile(SIMPLE_APP_DIFF_CERT_APK),
-                    true /* reinstall */, options);
-            assertNotNull("app upgrade with different cert than existing app installed " +
-                    "successfully", installResult);
-            assertEquals("INSTALL_FAILED_UPDATE_INCOMPATIBLE", installResult);
-        } finally {
-            getDevice().uninstallPackage(SIMPLE_APP_PKG);
-        }
-    }
-
-    /**
-     * Test that an app cannot access another app's private data.
-     */
-    public void testAppFailAccessPrivateData() throws Exception {
-        Log.i(LOG_TAG, "installing app that attempts to access another app's private data");
-        try {
-            // cleanup test app that might be installed from previous partial test run
-            getDevice().uninstallPackage(APP_WITH_DATA_PKG);
-            getDevice().uninstallPackage(APP_ACCESS_DATA_PKG);
-
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            String installResult = getDevice().installPackage(getTestAppFile(APP_WITH_DATA_APK),
-                    false, options);
-            assertNull(String.format("failed to install app with data. Reason: %s", installResult),
-                    installResult);
-            // run appwithdata's tests to create private data
-            runDeviceTests(APP_WITH_DATA_PKG, APP_WITH_DATA_CLASS, APP_WITH_DATA_CREATE_METHOD);
-
-            installResult = getDevice().installPackage(getTestAppFile(APP_ACCESS_DATA_APK),
-                    false, options);
-            assertNull(String.format("failed to install app access data. Reason: %s",
-                    installResult), installResult);
-            // run appaccessdata's tests which attempt to access appwithdata's private data
-            runDeviceTests(APP_ACCESS_DATA_PKG);
-        } finally {
-            getDevice().uninstallPackage(APP_WITH_DATA_PKG);
-            getDevice().uninstallPackage(APP_ACCESS_DATA_PKG);
-        }
-    }
-
-    /**
-     * Test that uninstall of an app removes its private data.
-     */
-    public void testUninstallRemovesData() throws Exception {
-        Log.i(LOG_TAG, "Uninstalling app, verifying data is removed.");
-        try {
-            // cleanup test app that might be installed from previous partial test run
-            getDevice().uninstallPackage(APP_WITH_DATA_PKG);
-
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            String installResult = getDevice().installPackage(getTestAppFile(APP_WITH_DATA_APK),
-                    false, options);
-            assertNull(String.format("failed to install app with data. Reason: %s", installResult),
-                    installResult);
-            // run appwithdata's tests to create private data
-            runDeviceTests(APP_WITH_DATA_PKG, APP_WITH_DATA_CLASS, APP_WITH_DATA_CREATE_METHOD);
-
-            getDevice().uninstallPackage(APP_WITH_DATA_PKG);
-
-            installResult = getDevice().installPackage(getTestAppFile(APP_WITH_DATA_APK),
-                    false, options);
-            assertNull(String.format("failed to install app with data second time. Reason: %s",
-                    installResult), installResult);
-            // run appwithdata's 'check if file exists' test
-            runDeviceTests(APP_WITH_DATA_PKG, APP_WITH_DATA_CLASS,
-                    APP_WITH_DATA_CHECK_NOEXIST_METHOD);
-        } finally {
-            getDevice().uninstallPackage(APP_WITH_DATA_PKG);
-        }
-    }
-
-    /**
-     * Test that an app cannot instrument another app that is signed with different certificate.
-     */
-    public void testInstrumentationDiffCert() throws Exception {
-        Log.i(LOG_TAG, "installing app that attempts to instrument another app");
-        try {
-            // cleanup test app that might be installed from previous partial test run
-            getDevice().uninstallPackage(TARGET_INSTRUMENT_PKG);
-            getDevice().uninstallPackage(INSTRUMENT_DIFF_CERT_PKG);
-
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            String installResult = getDevice().installPackage(
-                    getTestAppFile(TARGET_INSTRUMENT_APK), false, options);
-            assertNull(String.format("failed to install target instrumentation app. Reason: %s",
-                    installResult), installResult);
-
-            // the app will install, but will get error at runtime when starting instrumentation
-            installResult = getDevice().installPackage(getTestAppFile(INSTRUMENT_DIFF_CERT_APK),
-                    false, options);
-            assertNull(String.format(
-                    "failed to install instrumentation app with diff cert. Reason: %s",
-                    installResult), installResult);
-            // run INSTRUMENT_DIFF_CERT_PKG tests
-            // this test will attempt to call startInstrumentation directly and verify
-            // SecurityException is thrown
-            runDeviceTests(INSTRUMENT_DIFF_CERT_PKG);
-        } finally {
-            getDevice().uninstallPackage(TARGET_INSTRUMENT_PKG);
-            getDevice().uninstallPackage(INSTRUMENT_DIFF_CERT_PKG);
-        }
-    }
-
-    /**
-     * Test that an app cannot use a signature-enforced permission if it is signed with a different
-     * certificate than the app that declared the permission.
-     */
-    public void testPermissionDiffCert() throws Exception {
-        Log.i(LOG_TAG, "installing app that attempts to use permission of another app");
-        try {
-            // cleanup test app that might be installed from previous partial test run
-            getDevice().uninstallPackage(DECLARE_PERMISSION_PKG);
-            getDevice().uninstallPackage(DECLARE_PERMISSION_COMPAT_PKG);
-            getDevice().uninstallPackage(PERMISSION_DIFF_CERT_PKG);
-
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            String installResult = getDevice().installPackage(
-                    getTestAppFile(DECLARE_PERMISSION_APK), false, options);
-            assertNull(String.format("failed to install declare permission app. Reason: %s",
-                    installResult), installResult);
-
-            installResult = getDevice().installPackage(
-                    getTestAppFile(DECLARE_PERMISSION_COMPAT_APK), false, options);
-            assertNull(String.format("failed to install declare permission compat app. Reason: %s",
-                    installResult), installResult);
-
-            // the app will install, but will get error at runtime
-            installResult = getDevice().installPackage(getTestAppFile(PERMISSION_DIFF_CERT_APK),
-                    false, options);
-            assertNull(String.format("failed to install permission app with diff cert. Reason: %s",
-                    installResult), installResult);
-            // run PERMISSION_DIFF_CERT_PKG tests which try to access the permission
-            runDeviceTests(PERMISSION_DIFF_CERT_PKG);
-        } finally {
-            getDevice().uninstallPackage(DECLARE_PERMISSION_PKG);
-            getDevice().uninstallPackage(DECLARE_PERMISSION_COMPAT_PKG);
-            getDevice().uninstallPackage(PERMISSION_DIFF_CERT_PKG);
-        }
-    }
-
-    private void runDeviceTests(String packageName) throws DeviceNotAvailableException {
-        Utils.runDeviceTests(getDevice(), packageName);
-    }
-
-    private void runDeviceTests(String packageName, String testClassName, String testMethodName)
-            throws DeviceNotAvailableException {
-        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
-    }
-}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/DocumentsTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/DocumentsTest.java
deleted file mode 100644
index a4ec65a..0000000
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/DocumentsTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.appsecurity;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-/**
- * Set of tests that verify behavior of
- * {@link android.provider.DocumentsContract} and related intents.
- */
-public class DocumentsTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
-    private static final String PROVIDER_PKG = "com.android.cts.documentprovider";
-    private static final String PROVIDER_APK = "CtsDocumentProvider.apk";
-
-    private static final String CLIENT_PKG = "com.android.cts.documentclient";
-    private static final String CLIENT_APK = "CtsDocumentClient.apk";
-
-    private IAbi mAbi;
-    private CtsBuildHelper mCtsBuild;
-
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
-
-        getDevice().uninstallPackage(PROVIDER_PKG);
-        getDevice().uninstallPackage(CLIENT_PKG);
-
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(PROVIDER_APK), false));
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(CLIENT_APK), false));
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-
-        getDevice().uninstallPackage(PROVIDER_PKG);
-        getDevice().uninstallPackage(CLIENT_PKG);
-    }
-
-    public void testOpenSimple() throws Exception {
-        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testOpenSimple");
-    }
-
-    public void testCreateNew() throws Exception {
-        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testCreateNew");
-    }
-
-    public void testCreateExisting() throws Exception {
-        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testCreateExisting");
-    }
-
-    public void testTree() throws Exception {
-        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testTree");
-    }
-
-    public void testGetContent() throws Exception {
-        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testGetContent");
-    }
-
-    public void runDeviceTests(String packageName, String testClassName, String testMethodName)
-            throws DeviceNotAvailableException {
-        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
-    }
-}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/ExternalStorageHostTest.java
deleted file mode 100644
index 9c22bdc..0000000
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/ExternalStorageHostTest.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2015 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.appsecurity;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
-import com.android.ddmlib.Log;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-
-/**
- * Set of tests that verify behavior of external storage devices.
- */
-public class ExternalStorageHostTest extends DeviceTestCase
-        implements IAbiReceiver, IBuildReceiver {
-    private static final String TAG = "ExternalStorageHostTest";
-
-    private static final String COMMON_CLASS =
-            "com.android.cts.externalstorageapp.CommonExternalStorageTest";
-
-    private static final String NONE_APK = "CtsExternalStorageApp.apk";
-    private static final String NONE_PKG = "com.android.cts.externalstorageapp";
-    private static final String NONE_CLASS = ".ExternalStorageTest";
-    private static final String READ_APK = "CtsReadExternalStorageApp.apk";
-    private static final String READ_PKG = "com.android.cts.readexternalstorageapp";
-    private static final String READ_CLASS = ".ReadExternalStorageTest";
-    private static final String WRITE_APK = "CtsWriteExternalStorageApp.apk";
-    private static final String WRITE_PKG = "com.android.cts.writeexternalstorageapp";
-    private static final String WRITE_CLASS = ".WriteExternalStorageTest";
-    private static final String MULTIUSER_APK = "CtsMultiUserStorageApp.apk";
-    private static final String MULTIUSER_PKG = "com.android.cts.multiuserstorageapp";
-    private static final String MULTIUSER_CLASS = ".MultiUserStorageTest";
-
-    private IAbi mAbi;
-    private CtsBuildHelper mCtsBuild;
-
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return mCtsBuild.getTestApp(fileName);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    /**
-     * Verify that app with no external storage permissions works correctly.
-     */
-    public void testExternalStorageNone() throws Exception {
-        final int[] users = createUsersForTest();
-        try {
-            wipePrimaryExternalStorage();
-
-            getDevice().uninstallPackage(NONE_PKG);
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
-
-            for (int user : users) {
-                runDeviceTests(NONE_PKG, COMMON_CLASS, user);
-                runDeviceTests(NONE_PKG, NONE_CLASS, user);
-            }
-        } finally {
-            getDevice().uninstallPackage(NONE_PKG);
-            removeUsersForTest(users);
-        }
-    }
-
-    /**
-     * Verify that app with
-     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} works
-     * correctly.
-     */
-    public void testExternalStorageRead() throws Exception {
-        final int[] users = createUsersForTest();
-        try {
-            wipePrimaryExternalStorage();
-
-            getDevice().uninstallPackage(READ_PKG);
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
-
-            for (int user : users) {
-                runDeviceTests(READ_PKG, COMMON_CLASS, user);
-                runDeviceTests(READ_PKG, READ_CLASS, user);
-            }
-        } finally {
-            getDevice().uninstallPackage(READ_PKG);
-            removeUsersForTest(users);
-        }
-    }
-
-    /**
-     * Verify that app with
-     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} works
-     * correctly.
-     */
-    public void testExternalStorageWrite() throws Exception {
-        final int[] users = createUsersForTest();
-        try {
-            wipePrimaryExternalStorage();
-
-            getDevice().uninstallPackage(WRITE_PKG);
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
-
-            for (int user : users) {
-                runDeviceTests(WRITE_PKG, COMMON_CLASS, user);
-                runDeviceTests(WRITE_PKG, WRITE_CLASS, user);
-            }
-        } finally {
-            getDevice().uninstallPackage(WRITE_PKG);
-            removeUsersForTest(users);
-        }
-    }
-
-    /**
-     * Verify that app with WRITE_EXTERNAL can leave gifts in external storage
-     * directories belonging to other apps, and those apps can read.
-     */
-    public void testExternalStorageGifts() throws Exception {
-        final int[] users = createUsersForTest();
-        try {
-            wipePrimaryExternalStorage();
-
-            getDevice().uninstallPackage(NONE_PKG);
-            getDevice().uninstallPackage(READ_PKG);
-            getDevice().uninstallPackage(WRITE_PKG);
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
-            assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
-            assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
-
-            for (int user : users) {
-                runDeviceTests(WRITE_PKG, "WriteGiftTest", user);
-                runDeviceTests(READ_PKG, "ReadGiftTest", user);
-                runDeviceTests(NONE_PKG, "GiftTest", user);
-            }
-        } finally {
-            getDevice().uninstallPackage(NONE_PKG);
-            getDevice().uninstallPackage(READ_PKG);
-            getDevice().uninstallPackage(WRITE_PKG);
-            removeUsersForTest(users);
-        }
-    }
-
-    /**
-     * Test multi-user emulated storage environment, ensuring that each user has
-     * isolated storage.
-     */
-    public void testMultiUserStorageIsolated() throws Exception {
-        final int[] users = createUsersForTest();
-        try {
-            if (users.length == 1) {
-                Log.d(TAG, "Single user device; skipping isolated storage tests");
-                return;
-            }
-
-            final int owner = users[0];
-            final int secondary = users[1];
-
-            // Install our test app
-            getDevice().uninstallPackage(MULTIUSER_PKG);
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-            final String installResult = getDevice()
-                    .installPackage(getTestAppFile(MULTIUSER_APK), false, options);
-            assertNull("Failed to install: " + installResult, installResult);
-
-            // Clear data from previous tests
-            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testCleanIsolatedStorage", owner);
-            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testCleanIsolatedStorage", secondary);
-
-            // Have both users try writing into isolated storage
-            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testWriteIsolatedStorage", owner);
-            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testWriteIsolatedStorage", secondary);
-
-            // Verify they both have isolated view of storage
-            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testReadIsolatedStorage", owner);
-            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testReadIsolatedStorage", secondary);
-
-            // Verify they can't poke at each other
-            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testUserIsolation", owner);
-            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testUserIsolation", secondary);
-        } finally {
-            getDevice().uninstallPackage(MULTIUSER_PKG);
-            removeUsersForTest(users);
-        }
-    }
-
-    private void wipePrimaryExternalStorage() throws DeviceNotAvailableException {
-        getDevice().executeShellCommand("rm -rf /sdcard/Android");
-        getDevice().executeShellCommand("rm -rf /sdcard/DCIM");
-        getDevice().executeShellCommand("rm -rf /sdcard/MUST_*");
-    }
-
-    private int[] createUsersForTest() throws DeviceNotAvailableException {
-        return Utils.createUsersForTest(getDevice());
-    }
-
-    private void removeUsersForTest(int[] users) throws DeviceNotAvailableException {
-        Utils.removeUsersForTest(getDevice(), users);
-    }
-
-    private void runDeviceTests(String packageName, String testClassName, int userId)
-            throws DeviceNotAvailableException {
-        Utils.runDeviceTests(getDevice(), packageName, testClassName, userId);
-    }
-
-    private void runDeviceTests(String packageName, String testClassName, String testMethodName,
-            int userId) throws DeviceNotAvailableException {
-        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName, userId);
-    }
-}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java
deleted file mode 100644
index 9637a6c..0000000
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * 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.cts.appsecurity;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.Log.LogLevel;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
-import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.ddmlib.testrunner.TestResult;
-import com.android.ddmlib.testrunner.TestResult.TestStatus;
-import com.android.ddmlib.testrunner.TestRunResult;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.result.CollectingTestListener;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.Map;
-
-/**
- * Tests for Keyset based features.
- */
-public class KeySetHostTest extends DeviceTestCase implements IBuildReceiver {
-
-    private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
-
-    /* package with device-side tests */
-    private static final String KEYSET_TEST_PKG = "com.android.cts.keysets.testapp";
-    private static final String KEYSET_TEST_APP_APK = "CtsKeySetTestApp.apk";
-
-    /* plain test apks with different signing and upgrade keysets */
-    private static final String KEYSET_PKG = "com.android.cts.keysets";
-    private static final String A_SIGNED_NO_UPGRADE =
-            "CtsKeySetSigningAUpgradeNone.apk";
-    private static final String A_SIGNED_A_UPGRADE =
-            "CtsKeySetSigningAUpgradeA.apk";
-    private static final String A_SIGNED_B_UPGRADE =
-            "CtsKeySetSigningAUpgradeB.apk";
-    private static final String A_SIGNED_A_OR_B_UPGRADE =
-            "CtsKeySetSigningAUpgradeAOrB.apk";
-    private static final String B_SIGNED_A_UPGRADE =
-            "CtsKeySetSigningBUpgradeA.apk";
-    private static final String B_SIGNED_B_UPGRADE =
-            "CtsKeySetSigningBUpgradeB.apk";
-    private static final String A_AND_B_SIGNED_A_UPGRADE =
-            "CtsKeySetSigningAAndBUpgradeA.apk";
-    private static final String A_AND_B_SIGNED_B_UPGRADE =
-            "CtsKeySetSigningAAndBUpgradeB.apk";
-    private static final String A_AND_C_SIGNED_B_UPGRADE =
-            "CtsKeySetSigningAAndCUpgradeB.apk";
-    private static final String SHARED_USR_A_SIGNED_B_UPGRADE =
-            "CtsKeySetSharedUserSigningAUpgradeB.apk";
-    private static final String SHARED_USR_B_SIGNED_B_UPGRADE =
-            "CtsKeySetSharedUserSigningBUpgradeB.apk";
-    private static final String A_SIGNED_BAD_B_B_UPGRADE =
-            "CtsKeySetSigningABadUpgradeB.apk";
-    private static final String C_SIGNED_BAD_A_AB_UPGRADE =
-            "CtsKeySetSigningCBadAUpgradeAB.apk";
-    private static final String A_SIGNED_NO_B_B_UPGRADE =
-            "CtsKeySetSigningANoDefUpgradeB.apk";
-    private static final String A_SIGNED_EC_A_UPGRADE =
-            "CtsKeySetSigningAUpgradeEcA.apk";
-    private static final String EC_A_SIGNED_A_UPGRADE =
-            "CtsKeySetSigningEcAUpgradeA.apk";
-
-    /* package which defines the KEYSET_PERM_NAME signature permission */
-    private static final String KEYSET_PERM_DEF_PKG =
-            "com.android.cts.keysets_permdef";
-
-    /* The apks defining and using the permission have both A and B as upgrade keys */
-    private static final String PERM_DEF_A_SIGNED =
-            "CtsKeySetPermDefSigningA.apk";
-    private static final String PERM_DEF_B_SIGNED =
-            "CtsKeySetPermDefSigningB.apk";
-    private static final String PERM_USE_A_SIGNED =
-            "CtsKeySetPermUseSigningA.apk";
-    private static final String PERM_USE_B_SIGNED =
-            "CtsKeySetPermUseSigningB.apk";
-
-    private static final String PERM_TEST_CLASS =
-        "com.android.cts.keysets.KeySetPermissionsTest";
-
-    private static final String LOG_TAG = "AppsecurityHostTests";
-
-    private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return mCtsBuild.getTestApp(fileName);
-    }
-
-    /**
-     * Helper method that checks that all tests in given result passed, and attempts to generate
-     * a meaningful error message if they failed.
-     *
-     * @param result
-     */
-    private void assertDeviceTestsPass(TestRunResult result) {
-        assertFalse(String.format("Failed to successfully run device tests for %s. Reason: %s",
-                result.getName(), result.getRunFailureMessage()), result.isRunFailure());
-
-        if (result.hasFailedTests()) {
-
-            /* build a meaningful error message */
-            StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
-            for (Map.Entry<TestIdentifier, TestResult> resultEntry :
-                result.getTestResults().entrySet()) {
-                if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
-                    errorBuilder.append(resultEntry.getKey().toString());
-                    errorBuilder.append(":\n");
-                    errorBuilder.append(resultEntry.getValue().getStackTrace());
-                }
-            }
-            fail(errorBuilder.toString());
-        }
-    }
-
-    /**
-     * Helper method that checks that all tests in given result passed, and attempts to generate
-     * a meaningful error message if they failed.
-     *
-     * @param result
-     */
-    private void assertDeviceTestsFail(String msg, TestRunResult result) {
-        assertFalse(String.format("Failed to successfully run device tests for %s. Reason: %s",
-                result.getName(), result.getRunFailureMessage()), result.isRunFailure());
-
-        if (!result.hasFailedTests()) {
-            fail(msg);
-        }
-    }
-
-    /**
-     * Helper method that will run the specified packages tests on device.
-     *
-     * @param pkgName Android application package for tests
-     * @return <code>true</code> if all tests passed.
-     * @throws DeviceNotAvailableException if connection to device was lost.
-     */
-    private boolean runDeviceTests(String pkgName) throws DeviceNotAvailableException {
-        return runDeviceTests(pkgName, null, null);
-    }
-
-    /**
-     * Helper method that will run the specified packages tests on device.
-     *
-     * @param pkgName Android application package for tests
-     * @return <code>true</code> if all tests passed.
-     * @throws DeviceNotAvailableException if connection to device was lost.
-     */
-    private boolean runDeviceTests(String pkgName, String testClassName, String testMethodName)
-            throws DeviceNotAvailableException {
-        TestRunResult runResult = doRunTests(pkgName, testClassName, testMethodName);
-        return !runResult.hasFailedTests();
-    }
-
-    /**
-     * Helper method to run tests and return the listener that collected the results.
-     *
-     * @param pkgName Android application package for tests
-     * @return the {@link TestRunResult}
-     * @throws DeviceNotAvailableException if connection to device was lost.
-     */
-    private TestRunResult doRunTests(String pkgName, String testClassName,
-            String testMethodName) throws DeviceNotAvailableException {
-
-        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(pkgName,
-                RUNNER, getDevice().getIDevice());
-        if (testClassName != null && testMethodName != null) {
-            testRunner.setMethodName(testClassName, testMethodName);
-        }
-        CollectingTestListener listener = new CollectingTestListener();
-        getDevice().runInstrumentationTests(testRunner, listener);
-        return listener.getCurrentRunResults();
-    }
-
-    /**
-     * Helper method which installs a package and an upgrade to it.
-     *
-     * @param pkgName - package name of apk.
-     * @param firstApk - first apk to install
-     * @param secondApk - apk to which we attempt to upgrade
-     * @param expectedResult - null if successful, otherwise expected error.
-     */
-    private String testPackageUpgrade(String pkgName, String firstApk,
-             String secondApk) throws Exception {
-        String installResult;
-        try {
-
-            /* cleanup test apps that might be installed from previous partial test run */
-            mDevice.uninstallPackage(pkgName);
-
-            installResult = mDevice.installPackage(getTestAppFile(firstApk),
-                    false);
-            /* we should always succeed on first-install */
-            assertNull(String.format("failed to install %s, Reason: %s", pkgName,
-                       installResult), installResult);
-
-            /* attempt to install upgrade */
-            installResult = mDevice.installPackage(getTestAppFile(secondApk),
-                    true);
-        } finally {
-            mDevice.uninstallPackage(pkgName);
-        }
-        return installResult;
-    }
-    /**
-     * A reference to the device under test.
-     */
-    private ITestDevice mDevice;
-
-    private CtsBuildHelper mCtsBuild;
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-        protected void setUp() throws Exception {
-        super.setUp();
-        mDevice = getDevice();
-        assertNotNull(mCtsBuild);
-    }
-
-    /**
-     * Tests for KeySet based key rotation
-     */
-
-    /*
-     * Check if an apk which does not specify an upgrade-key-set may be upgraded
-     * to an apk which does.
-     */
-    public void testNoKSToUpgradeKS() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_NO_UPGRADE, A_SIGNED_A_UPGRADE);
-        assertNull(String.format("failed to upgrade keyset app from no specified upgrade-key-set"
-                + "to version with specified upgrade-key-set, Reason: %s", installResult),
-                installResult);
-    }
-
-    /*
-     * Check if an apk which does specify an upgrade-key-set may be upgraded
-     * to an apk which does not.
-     */
-    public void testUpgradeKSToNoKS() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE, A_SIGNED_NO_UPGRADE);
-        assertNull(String.format("failed to upgrade keyset app from specified upgrade-key-set"
-                + "to version without specified upgrade-key-set, Reason: %s", installResult),
-                installResult);
-    }
-
-    /*
-     * Check if an apk signed by a key other than the upgrade keyset can update
-     * an app
-     */
-    public void testUpgradeKSWithWrongKey() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE, B_SIGNED_A_UPGRADE);
-        assertNotNull("upgrade to improperly signed app succeeded!", installResult);
-    }
-
-    /*
-     * Check if an apk signed by its signing key, which is not an upgrade key,
-     * can upgrade an app.
-     */
-    public void testUpgradeKSWithWrongSigningKey() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_B_UPGRADE, A_SIGNED_B_UPGRADE);
-         assertNotNull("upgrade to improperly signed app succeeded!",
-                 installResult);
-    }
-
-    /*
-     * Check if an apk signed by its upgrade key, which is not its signing key,
-     * can upgrade an app.
-     */
-    public void testUpgradeKSWithUpgradeKey() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_B_UPGRADE, B_SIGNED_B_UPGRADE);
-        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
-                 + "to version signed by upgrade-key-set key-b, Reason: %s", installResult),
-                 installResult);
-    }
-
-    /*
-     * Check if an apk signed by its upgrade key, which is its signing key, can
-     * upgrade an app.
-     */
-    public void testUpgradeKSWithSigningUpgradeKey() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE, A_SIGNED_A_UPGRADE);
-        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
-                    + "to version signed by upgrade-key-set key-b, Reason: %s", installResult),
-                    installResult);
-    }
-
-    /*
-     * Check if an apk signed by multiple keys, one of which is its upgrade key,
-     * can upgrade an app.
-     */
-    public void testMultipleUpgradeKSWithUpgradeKey() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE,
-                A_AND_B_SIGNED_A_UPGRADE);
-        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
-                + "to version signed by upgrade-key-set key-b, Reason: %s", installResult),
-                installResult);
-    }
-
-    /*
-     * Check if an apk signed by multiple keys, its signing keys,
-     * but none of which is an upgrade key, can upgrade an app.
-     */
-    public void testMultipleUpgradeKSWithSigningKey() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, A_AND_C_SIGNED_B_UPGRADE,
-                A_AND_C_SIGNED_B_UPGRADE);
-        assertNotNull("upgrade to improperly signed app succeeded!", installResult);
-    }
-
-    /*
-     * Check if an apk which defines multiple (two) upgrade keysets is
-     * upgrade-able by either.
-     */
-    public void testUpgradeKSWithMultipleUpgradeKeySetsFirstKey() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_OR_B_UPGRADE,
-                A_SIGNED_A_UPGRADE);
-        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
-                + "to one signed by first upgrade keyset key-a, Reason: %s", installResult),
-                installResult);
-        installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_OR_B_UPGRADE,
-                B_SIGNED_B_UPGRADE);
-        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
-                + "to one signed by second upgrade keyset key-b, Reason: %s", installResult),
-                installResult);
-    }
-
-    /**
-     * Helper method which installs a package defining a permission and a package
-     * using the permission, and then rotates the signing keys for one of them.
-     * A device-side test is then used to ascertain whether or not the permission
-     * was appropriately gained or lost.
-     *
-     * @param permDefApk - apk to install which defines the sig-permissoin
-     * @param permUseApk - apk to install which declares it uses the permission
-     * @param upgradeApk - apk to install which upgrades one of the first two
-     * @param hasPermBeforeUpgrade - whether we expect the consuming app to have
-     *        the permission before the upgrade takes place.
-     * @param hasPermAfterUpgrade - whether we expect the consuming app to have
-     *        the permission after the upgrade takes place.
-     */
-    private void testKeyRotationPerm(String permDefApk, String permUseApk,
-            String upgradeApk, boolean hasPermBeforeUpgrade,
-            boolean hasPermAfterUpgrade) throws Exception {
-        try {
-
-            /* cleanup test apps that might be installed from previous partial test run */
-            mDevice.uninstallPackage(KEYSET_PKG);
-            mDevice.uninstallPackage(KEYSET_PERM_DEF_PKG);
-            mDevice.uninstallPackage(KEYSET_TEST_PKG);
-
-            /* install PERM_DEF, KEYSET_APP and KEYSET_TEST_APP */
-            String installResult = mDevice.installPackage(
-                    getTestAppFile(permDefApk), false);
-            assertNull(String.format("failed to install keyset perm-def app, Reason: %s",
-                       installResult), installResult);
-            installResult = getDevice().installPackage(
-                    getTestAppFile(permUseApk), false);
-            assertNull(String.format("failed to install keyset test app. Reason: %s",
-                    installResult), installResult);
-            installResult = getDevice().installPackage(
-                    getTestAppFile(KEYSET_TEST_APP_APK), false);
-            assertNull(String.format("failed to install keyset test app. Reason: %s",
-                    installResult), installResult);
-
-            /* verify package does have perm */
-            TestRunResult result = doRunTests(KEYSET_TEST_PKG, PERM_TEST_CLASS,
-                    "testHasPerm");
-            if (hasPermBeforeUpgrade) {
-                assertDeviceTestsPass(result);
-            } else {
-                assertDeviceTestsFail(" has permission permission it should not have.", result);
-            }
-
-            /* rotate keys */
-            installResult = mDevice.installPackage(getTestAppFile(upgradeApk),
-                    true);
-            result = doRunTests(KEYSET_TEST_PKG, PERM_TEST_CLASS,
-                    "testHasPerm");
-            if (hasPermAfterUpgrade) {
-                assertDeviceTestsPass(result);
-            } else {
-                assertDeviceTestsFail(KEYSET_PKG + " has permission it should not have.", result);
-            }
-        } finally {
-            mDevice.uninstallPackage(KEYSET_PKG);
-            mDevice.uninstallPackage(KEYSET_PERM_DEF_PKG);
-            mDevice.uninstallPackage(KEYSET_TEST_PKG);
-        }
-    }
-
-    /*
-     * Check if an apk gains signature-level permission after changing to a new
-     * signature, for which a permission should be granted.
-     */
-    public void testUpgradeSigPermGained() throws Exception {
-        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_B_SIGNED, PERM_USE_A_SIGNED,
-                false, true);
-    }
-
-    /*
-     * Check if an apk loses signature-level permission after changing to a new
-     * signature, from one for which a permission was previously granted.
-     */
-    public void testUpgradeSigPermLost() throws Exception {
-        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_A_SIGNED, PERM_USE_B_SIGNED,
-                true, false);
-    }
-
-    /*
-     * Check if an apk gains signature-level permission after the app defining
-     * it rotates to the same signature.
-     */
-    public void testUpgradeDefinerSigPermGained() throws Exception {
-        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_B_SIGNED, PERM_DEF_B_SIGNED,
-                false, true);
-    }
-
-    /*
-     * Check if an apk loses signature-level permission after the app defining
-     * it rotates to a different signature.
-     */
-    public void testUpgradeDefinerSigPermLost() throws Exception {
-        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_A_SIGNED, PERM_DEF_B_SIGNED,
-                true, false);
-    }
-
-    /*
-     * Check if an apk which indicates it uses a sharedUserId and defines an
-     * upgrade keyset is allowed to rotate to that keyset.
-     */
-    public void testUpgradeSharedUser() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, SHARED_USR_A_SIGNED_B_UPGRADE,
-                SHARED_USR_B_SIGNED_B_UPGRADE);
-        assertNotNull("upgrade allowed for app with shareduserid!", installResult);
-    }
-
-    /*
-     * Check that an apk with an upgrade key represented by a bad public key
-     * fails to install.
-     */
-    public void testBadUpgradeBadPubKey() throws Exception {
-        mDevice.uninstallPackage(KEYSET_PKG);
-        String installResult = mDevice.installPackage(getTestAppFile(A_SIGNED_BAD_B_B_UPGRADE),
-                false);
-        assertNotNull("Installation of apk with upgrade key referring to a bad public key succeeded!",
-                installResult);
-    }
-
-    /*
-     * Check that an apk with an upgrade keyset that includes a bad public key fails to install.
-     */
-    public void testBadUpgradeMissingPubKey() throws Exception {
-        mDevice.uninstallPackage(KEYSET_PKG);
-        String installResult = mDevice.installPackage(getTestAppFile(C_SIGNED_BAD_A_AB_UPGRADE),
-                false);
-        assertNotNull("Installation of apk with upgrade key referring to a bad public key succeeded!",
-                installResult);
-    }
-
-    /*
-     * Check that an apk with an upgrade key that has no corresponding public key fails to install.
-     */
-    public void testBadUpgradeNoPubKey() throws Exception {
-        mDevice.uninstallPackage(KEYSET_PKG);
-        String installResult = mDevice.installPackage(getTestAppFile(A_SIGNED_NO_B_B_UPGRADE),
-                false);
-        assertNotNull("Installation of apk with upgrade key referring to a bad public key succeeded!",
-                installResult);
-    }
-
-    /*
-     * Check if an apk signed by RSA pub key can upgrade to apk signed by EC key.
-     */
-    public void testUpgradeKSRsaToEC() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_EC_A_UPGRADE,
-                EC_A_SIGNED_A_UPGRADE);
-        assertNull(String.format("failed to upgrade keyset app from one signed by RSA key"
-                 + "to version signed by EC upgrade-key-set, Reason: %s", installResult),
-                 installResult);
-    }
-
-    /*
-     * Check if an apk signed by EC pub key can upgrade to apk signed by RSA key.
-     */
-    public void testUpgradeKSECToRSA() throws Exception {
-        String installResult = testPackageUpgrade(KEYSET_PKG, EC_A_SIGNED_A_UPGRADE,
-                A_SIGNED_EC_A_UPGRADE);
-        assertNull(String.format("failed to upgrade keyset app from one signed by EC key"
-                 + "to version signed by RSA upgrade-key-set, Reason: %s", installResult),
-                 installResult);
-    }
-}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/PermissionsHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/PermissionsHostTest.java
deleted file mode 100644
index 20a92aa..0000000
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/PermissionsHostTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2015 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.appsecurity;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-/**
- * Set of tests that verify behavior of runtime permissions, including both
- * dynamic granting and behavior of legacy apps.
- */
-public class PermissionsHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
-    private static final String PKG = "com.android.cts.usepermission";
-
-    private static final String APK = "CtsUsePermissionApp.apk";
-    private static final String APK_COMPAT = "CtsUsePermissionAppCompat.apk";
-
-    private IAbi mAbi;
-    private CtsBuildHelper mCtsBuild;
-
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
-
-        getDevice().uninstallPackage(PKG);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-
-        getDevice().uninstallPackage(PKG);
-    }
-
-    public void testFail() throws Exception {
-        // Sanity check that remote failure is host failure
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
-        try {
-            runDeviceTests(PKG, ".UsePermissionTest", "testFail");
-            fail("Expected remote failure");
-        } catch (AssertionError expected) {
-        }
-    }
-
-    public void testKill() throws Exception {
-        // Sanity check that remote kill is host failure
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
-        try {
-            runDeviceTests(PKG, ".UsePermissionTest", "testKill");
-            fail("Expected remote failure");
-        } catch (AssertionError expected) {
-        }
-    }
-
-    public void testDefault() throws Exception {
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
-        runDeviceTests(PKG, ".UsePermissionTest", "testDefault");
-    }
-
-    public void testGranted() throws Exception {
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
-        grantPermission(PKG, "android.permission.READ_EXTERNAL_STORAGE");
-        grantPermission(PKG, "android.permission.WRITE_EXTERNAL_STORAGE");
-        runDeviceTests(PKG, ".UsePermissionTest", "testGranted");
-    }
-
-    public void testInteractiveGrant() throws Exception {
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
-        runDeviceTests(PKG, ".UsePermissionTest", "testInteractiveGrant");
-    }
-
-    public void testRuntimeGroupGrantSpecificity() throws Exception {
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
-        runDeviceTests(PKG, ".UsePermissionTest", "testRuntimeGroupGrantSpecificity");
-    }
-
-    public void testRuntimeGroupGrantExpansion() throws Exception {
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
-        runDeviceTests(PKG, ".UsePermissionTest", "testRuntimeGroupGrantExpansion");
-    }
-
-    public void testCompatDefault() throws Exception {
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK_COMPAT), false, false));
-        runDeviceTests(PKG, ".UsePermissionCompatTest", "testCompatDefault");
-    }
-
-    public void testCompatRevoked() throws Exception {
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK_COMPAT), false, false));
-        setAppOps(PKG, "android:read_external_storage", "deny");
-        setAppOps(PKG, "android:write_external_storage", "deny");
-        runDeviceTests(PKG, ".UsePermissionCompatTest", "testCompatRevoked");
-    }
-
-    private void runDeviceTests(String packageName, String testClassName, String testMethodName)
-            throws DeviceNotAvailableException {
-        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
-    }
-
-    private void grantPermission(String pkg, String permission) throws Exception {
-        assertEmpty(getDevice().executeShellCommand("pm grant " + pkg + " " + permission));
-    }
-
-    private void revokePermission(String pkg, String permission) throws Exception {
-        assertEmpty(getDevice().executeShellCommand("pm revoke " + pkg + " " + permission));
-    }
-
-    private void setAppOps(String pkg, String op, String mode) throws Exception {
-        assertEmpty(getDevice().executeShellCommand("appops set " + pkg + " " + op + " " + mode));
-    }
-
-    private static void assertEmpty(String str) {
-        if (str == null || str.length() == 0) {
-            return;
-        } else {
-            fail("Expected empty string but found " + str);
-        }
-    }
-}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/SplitTests.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/SplitTests.java
deleted file mode 100644
index ef3af8d..0000000
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/SplitTests.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * 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.appsecurity;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Tests that verify installing of various split APKs from host side.
- */
-public class SplitTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
-    static final String PKG = "com.android.cts.splitapp";
-    static final String CLASS = ".SplitAppTest";
-
-    static final String APK = "CtsSplitApp.apk";
-
-    static final String APK_mdpi = "CtsSplitApp_mdpi-v4.apk";
-    static final String APK_hdpi = "CtsSplitApp_hdpi-v4.apk";
-    static final String APK_xhdpi = "CtsSplitApp_xhdpi-v4.apk";
-    static final String APK_xxhdpi = "CtsSplitApp_xxhdpi-v4.apk";
-
-    private static final String APK_v7 = "CtsSplitApp_v7.apk";
-    private static final String APK_fr = "CtsSplitApp_fr.apk";
-    private static final String APK_de = "CtsSplitApp_de.apk";
-
-    private static final String APK_x86 = "CtsSplitApp_x86.apk";
-    private static final String APK_x86_64 = "CtsSplitApp_x86_64.apk";
-    private static final String APK_armeabi_v7a = "CtsSplitApp_armeabi-v7a.apk";
-    private static final String APK_armeabi = "CtsSplitApp_armeabi.apk";
-    private static final String APK_arm64_v8a = "CtsSplitApp_arm64-v8a.apk";
-    private static final String APK_mips64 = "CtsSplitApp_mips64.apk";
-    private static final String APK_mips = "CtsSplitApp_mips.apk";
-
-    private static final String APK_DIFF_REVISION = "CtsSplitAppDiffRevision.apk";
-    private static final String APK_DIFF_REVISION_v7 = "CtsSplitAppDiffRevision_v7.apk";
-
-    private static final String APK_DIFF_VERSION = "CtsSplitAppDiffVersion.apk";
-    private static final String APK_DIFF_VERSION_v7 = "CtsSplitAppDiffVersion_v7.apk";
-
-    private static final String APK_DIFF_CERT = "CtsSplitAppDiffCert.apk";
-    private static final String APK_DIFF_CERT_v7 = "CtsSplitAppDiffCert_v7.apk";
-
-    private static final String APK_FEATURE = "CtsSplitAppFeature.apk";
-    private static final String APK_FEATURE_v7 = "CtsSplitAppFeature_v7.apk";
-
-    static final HashMap<String, String> ABI_TO_APK = new HashMap<>();
-
-    static {
-        ABI_TO_APK.put("x86", APK_x86);
-        ABI_TO_APK.put("x86_64", APK_x86_64);
-        ABI_TO_APK.put("armeabi-v7a", APK_armeabi_v7a);
-        ABI_TO_APK.put("armeabi", APK_armeabi);
-        ABI_TO_APK.put("arm64-v8a", APK_arm64_v8a);
-        ABI_TO_APK.put("mips64", APK_mips64);
-        ABI_TO_APK.put("mips", APK_mips);
-    }
-
-    private IAbi mAbi;
-    private CtsBuildHelper mCtsBuild;
-
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
-
-        getDevice().uninstallPackage(PKG);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-
-        getDevice().uninstallPackage(PKG);
-    }
-
-    public void testSingleBase() throws Exception {
-        new InstallMultiple().addApk(APK).run();
-        runDeviceTests(PKG, CLASS, "testSingleBase");
-    }
-
-    public void testDensitySingle() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_mdpi).run();
-        runDeviceTests(PKG, CLASS, "testDensitySingle");
-    }
-
-    public void testDensityAll() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_mdpi).addApk(APK_hdpi).addApk(APK_xhdpi)
-                .addApk(APK_xxhdpi).run();
-        runDeviceTests(PKG, CLASS, "testDensityAll");
-    }
-
-    /**
-     * Install first with low-resolution resources, then add a split that offers
-     * higher-resolution resources.
-     */
-    public void testDensityBest() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_mdpi).run();
-        runDeviceTests(PKG, CLASS, "testDensityBest1");
-
-        // Now splice in an additional split which offers better resources
-        new InstallMultiple().inheritFrom(PKG).addApk(APK_xxhdpi).run();
-        runDeviceTests(PKG, CLASS, "testDensityBest2");
-    }
-
-    /**
-     * Verify that an API-based split can change enabled/disabled state of
-     * manifest elements.
-     */
-    public void testApi() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_v7).run();
-        runDeviceTests(PKG, CLASS, "testApi");
-    }
-
-    public void testLocale() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_de).addApk(APK_fr).run();
-        runDeviceTests(PKG, CLASS, "testLocale");
-    }
-
-    /**
-     * Install test app with <em>single</em> split that exactly matches the
-     * currently active ABI. This also explicitly forces ABI when installing.
-     */
-    public void testNativeSingle() throws Exception {
-        final String abi = mAbi.getName();
-        final String apk = ABI_TO_APK.get(abi);
-        assertNotNull("Failed to find APK for ABI " + abi, apk);
-
-        new InstallMultiple().addApk(APK).addApk(apk).run();
-        runDeviceTests(PKG, CLASS, "testNative");
-    }
-
-    /**
-     * Install test app with <em>single</em> split that exactly matches the
-     * currently active ABI. This variant <em>does not</em> force the ABI when
-     * installing, instead exercising the system's ability to choose the ABI
-     * through inspection of the installed app.
-     */
-    public void testNativeSingleNatural() throws Exception {
-        final String abi = mAbi.getName();
-        final String apk = ABI_TO_APK.get(abi);
-        assertNotNull("Failed to find APK for ABI " + abi, apk);
-
-        new InstallMultiple().useNaturalAbi().addApk(APK).addApk(apk).run();
-        runDeviceTests(PKG, CLASS, "testNative");
-    }
-
-    /**
-     * Install test app with <em>all</em> possible ABI splits. This also
-     * explicitly forces ABI when installing.
-     */
-    public void testNativeAll() throws Exception {
-        final InstallMultiple inst = new InstallMultiple().addApk(APK);
-        for (String apk : ABI_TO_APK.values()) {
-            inst.addApk(apk);
-        }
-        inst.run();
-        runDeviceTests(PKG, CLASS, "testNative");
-    }
-
-    /**
-     * Install test app with <em>all</em> possible ABI splits. This variant
-     * <em>does not</em> force the ABI when installing, instead exercising the
-     * system's ability to choose the ABI through inspection of the installed
-     * app.
-     */
-    public void testNativeAllNatural() throws Exception {
-        final InstallMultiple inst = new InstallMultiple().useNaturalAbi().addApk(APK);
-        for (String apk : ABI_TO_APK.values()) {
-            inst.addApk(apk);
-        }
-        inst.run();
-        runDeviceTests(PKG, CLASS, "testNative");
-    }
-
-    public void testDuplicateBase() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK).runExpectingFailure();
-    }
-
-    public void testDuplicateSplit() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_v7).addApk(APK_v7).runExpectingFailure();
-    }
-
-    public void testDiffCert() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_DIFF_CERT_v7).runExpectingFailure();
-    }
-
-    public void testDiffCertInherit() throws Exception {
-        new InstallMultiple().addApk(APK).run();
-        new InstallMultiple().inheritFrom(PKG).addApk(APK_DIFF_CERT_v7).runExpectingFailure();
-    }
-
-    public void testDiffVersion() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_DIFF_VERSION_v7).runExpectingFailure();
-    }
-
-    public void testDiffVersionInherit() throws Exception {
-        new InstallMultiple().addApk(APK).run();
-        new InstallMultiple().inheritFrom(PKG).addApk(APK_DIFF_VERSION_v7).runExpectingFailure();
-    }
-
-    public void testDiffRevision() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_DIFF_REVISION_v7).run();
-        runDeviceTests(PKG, CLASS, "testRevision0_12");
-    }
-
-    public void testDiffRevisionInheritBase() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_v7).run();
-        runDeviceTests(PKG, CLASS, "testRevision0_0");
-        new InstallMultiple().inheritFrom(PKG).addApk(APK_DIFF_REVISION_v7).run();
-        runDeviceTests(PKG, CLASS, "testRevision0_12");
-    }
-
-    public void testDiffRevisionInheritSplit() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_v7).run();
-        runDeviceTests(PKG, CLASS, "testRevision0_0");
-        new InstallMultiple().inheritFrom(PKG).addApk(APK_DIFF_REVISION).run();
-        runDeviceTests(PKG, CLASS, "testRevision12_0");
-    }
-
-    public void testDiffRevisionDowngrade() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_DIFF_REVISION_v7).run();
-        new InstallMultiple().inheritFrom(PKG).addApk(APK_v7).runExpectingFailure();
-    }
-
-    public void testFeatureBase() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_FEATURE).run();
-        runDeviceTests(PKG, CLASS, "testFeatureBase");
-    }
-
-    public void testFeatureApi() throws Exception {
-        new InstallMultiple().addApk(APK).addApk(APK_FEATURE).addApk(APK_FEATURE_v7).run();
-        runDeviceTests(PKG, CLASS, "testFeatureApi");
-    }
-
-    public void testInheritUpdatedBase() throws Exception {
-        // TODO: flesh out this test
-    }
-
-    public void testInheritUpdatedSplit() throws Exception {
-        // TODO: flesh out this test
-    }
-
-    /**
-     * Verify that installing a new version of app wipes code cache.
-     */
-    public void testClearCodeCache() throws Exception {
-        new InstallMultiple().addApk(APK).run();
-        runDeviceTests(PKG, CLASS, "testCodeCacheWrite");
-        new InstallMultiple().addArg("-r").addApk(APK_DIFF_VERSION).run();
-        runDeviceTests(PKG, CLASS, "testCodeCacheRead");
-    }
-
-    private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
-        public InstallMultiple() {
-            super(getDevice(), mCtsBuild, mAbi);
-        }
-    }
-
-    public static class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
-        private final ITestDevice mDevice;
-        private final CtsBuildHelper mBuild;
-        private final IAbi mAbi;
-
-        private final List<String> mArgs = new ArrayList<>();
-        private final List<File> mApks = new ArrayList<>();
-        private boolean mUseNaturalAbi;
-
-        public BaseInstallMultiple(ITestDevice device, CtsBuildHelper build, IAbi abi) {
-            mDevice = device;
-            mBuild = build;
-            mAbi = abi;
-            addArg("-g");
-        }
-
-        T addArg(String arg) {
-            mArgs.add(arg);
-            return (T) this;
-        }
-
-        T addApk(String apk) throws FileNotFoundException {
-            mApks.add(mBuild.getTestApp(apk));
-            return (T) this;
-        }
-
-        T inheritFrom(String packageName) {
-            addArg("-r");
-            addArg("-p " + packageName);
-            return (T) this;
-        }
-
-        T useNaturalAbi() {
-            mUseNaturalAbi = true;
-            return (T) this;
-        }
-
-        T locationAuto() {
-            addArg("--install-location 0");
-            return (T) this;
-        }
-
-        T locationInternalOnly() {
-            addArg("--install-location 1");
-            return (T) this;
-        }
-
-        T locationPreferExternal() {
-            addArg("--install-location 2");
-            return (T) this;
-        }
-
-        T forceUuid(String uuid) {
-            addArg("--force-uuid " + uuid);
-            return (T) this;
-        }
-
-        void run() throws DeviceNotAvailableException {
-            run(true);
-        }
-
-        void runExpectingFailure() throws DeviceNotAvailableException {
-            run(false);
-        }
-
-        private void run(boolean expectingSuccess) throws DeviceNotAvailableException {
-            final ITestDevice device = mDevice;
-
-            // Create an install session
-            final StringBuilder cmd = new StringBuilder();
-            cmd.append("pm install-create");
-            for (String arg : mArgs) {
-                cmd.append(' ').append(arg);
-            }
-            if (!mUseNaturalAbi) {
-                cmd.append(' ').append(AbiUtils.createAbiFlag(mAbi.getName()));
-            }
-
-            String result = device.executeShellCommand(cmd.toString());
-            assertTrue(result, result.startsWith("Success"));
-
-            final int start = result.lastIndexOf("[");
-            final int end = result.lastIndexOf("]");
-            int sessionId = -1;
-            try {
-                if (start != -1 && end != -1 && start < end) {
-                    sessionId = Integer.parseInt(result.substring(start + 1, end));
-                }
-            } catch (NumberFormatException e) {
-            }
-            if (sessionId == -1) {
-                throw new IllegalStateException("Failed to create install session: " + result);
-            }
-
-            // Push our files into session. Ideally we'd use stdin streaming,
-            // but ddmlib doesn't support it yet.
-            for (int i = 0; i < mApks.size(); i++) {
-                final File apk = mApks.get(i);
-                final String remotePath = "/data/local/tmp/" + i + "_" + apk.getName();
-                if (!device.pushFile(apk, remotePath)) {
-                    throw new IllegalStateException("Failed to push " + apk);
-                }
-
-                cmd.setLength(0);
-                cmd.append("pm install-write");
-                cmd.append(' ').append(sessionId);
-                cmd.append(' ').append(i + "_" + apk.getName());
-                cmd.append(' ').append(remotePath);
-
-                result = device.executeShellCommand(cmd.toString());
-                assertTrue(result, result.startsWith("Success"));
-            }
-
-            // Everything staged; let's pull trigger
-            cmd.setLength(0);
-            cmd.append("pm install-commit");
-            cmd.append(' ').append(sessionId);
-
-            result = device.executeShellCommand(cmd.toString());
-            if (expectingSuccess) {
-                assertTrue(result, result.startsWith("Success"));
-            } else {
-                assertFalse(result, result.startsWith("Success"));
-            }
-        }
-    }
-
-    public void runDeviceTests(String packageName, String testClassName, String testMethodName)
-            throws DeviceNotAvailableException {
-        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
-    }
-}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/Utils.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/Utils.java
deleted file mode 100644
index fdf84d3..0000000
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/Utils.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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.appsecurity;
-
-import com.android.ddmlib.Log;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
-import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.ddmlib.testrunner.TestResult;
-import com.android.ddmlib.testrunner.TestResult.TestStatus;
-import com.android.ddmlib.testrunner.TestRunResult;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.result.CollectingTestListener;
-
-import java.util.Map;
-
-public class Utils {
-    private static final String TAG = "AppSecurity";
-
-    public static final int USER_OWNER = 0;
-
-    public static void runDeviceTests(ITestDevice device, String packageName)
-            throws DeviceNotAvailableException {
-        runDeviceTests(device, packageName, null, null, USER_OWNER);
-    }
-
-    public static void runDeviceTests(ITestDevice device, String packageName, int userId)
-            throws DeviceNotAvailableException {
-        runDeviceTests(device, packageName, null, null, userId);
-    }
-
-    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName)
-            throws DeviceNotAvailableException {
-        runDeviceTests(device, packageName, testClassName, null, USER_OWNER);
-    }
-
-    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
-            int userId) throws DeviceNotAvailableException {
-        runDeviceTests(device, packageName, testClassName, null, userId);
-    }
-
-    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
-            String testMethodName) throws DeviceNotAvailableException {
-        runDeviceTests(device, packageName, testClassName, testMethodName, USER_OWNER);
-    }
-
-    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
-            String testMethodName, int userId) throws DeviceNotAvailableException {
-        if (testClassName != null && testClassName.startsWith(".")) {
-            testClassName = packageName + testClassName;
-        }
-
-        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName,
-                "android.support.test.runner.AndroidJUnitRunner", device.getIDevice());
-        if (testClassName != null && testMethodName != null) {
-            testRunner.setMethodName(testClassName, testMethodName);
-        } else if (testClassName != null) {
-            testRunner.setClassName(testClassName);
-        }
-
-        if (userId != USER_OWNER) {
-            // TODO: move this to RemoteAndroidTestRunner once it supports users
-            testRunner.addInstrumentationArg("hack_key", "hack_value --user " + userId);
-        }
-
-        final CollectingTestListener listener = new CollectingTestListener();
-        device.runInstrumentationTests(testRunner, listener);
-
-        final TestRunResult result = listener.getCurrentRunResults();
-        if (result.isRunFailure()) {
-            throw new AssertionError("Failed to successfully run device tests for "
-                    + result.getName() + ": " + result.getRunFailureMessage());
-        }
-
-        if (result.hasFailedTests()) {
-            // build a meaningful error message
-            StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
-            for (Map.Entry<TestIdentifier, TestResult> resultEntry :
-                result.getTestResults().entrySet()) {
-                if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
-                    errorBuilder.append(resultEntry.getKey().toString());
-                    errorBuilder.append(":\n");
-                    errorBuilder.append(resultEntry.getValue().getStackTrace());
-                }
-            }
-            throw new AssertionError(errorBuilder.toString());
-        }
-    }
-
-    private static boolean isMultiUserSupportedOnDevice(ITestDevice device)
-            throws DeviceNotAvailableException {
-        // TODO: move this to ITestDevice once it supports users
-        final String output = device.executeShellCommand("pm get-max-users");
-        try {
-            return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim()) > 1;
-        } catch (NumberFormatException e) {
-            throw new AssertionError("Failed to parse result: " + output);
-        }
-    }
-
-    /**
-     * Return set of users that test should be run for, creating a secondary
-     * user if the device supports it. Always call
-     * {@link #removeUsersForTest(ITestDevice, int[])} when finished.
-     */
-    public static int[] createUsersForTest(ITestDevice device) throws DeviceNotAvailableException {
-        if (isMultiUserSupportedOnDevice(device)) {
-            return new int[] { USER_OWNER, createUserOnDevice(device) };
-        } else {
-            Log.d(TAG, "Single user device; skipping isolated storage tests");
-            return new int[] { USER_OWNER };
-        }
-    }
-
-    public static void removeUsersForTest(ITestDevice device, int[] users)
-            throws DeviceNotAvailableException {
-        for (int user : users) {
-            if (user != USER_OWNER) {
-                removeUserOnDevice(device, user);
-            }
-        }
-    }
-
-    private static int createUserOnDevice(ITestDevice device) throws DeviceNotAvailableException {
-        // TODO: move this to ITestDevice once it supports users
-        final String name = "CTS_" + System.currentTimeMillis();
-        final String output = device.executeShellCommand("pm create-user " + name);
-        if (output.startsWith("Success")) {
-            try {
-                final int userId = Integer.parseInt(
-                        output.substring(output.lastIndexOf(" ")).trim());
-                device.executeShellCommand("am start-user " + userId);
-                return userId;
-            } catch (NumberFormatException e) {
-                throw new AssertionError("Failed to parse result: " + output);
-            }
-        } else {
-            throw new AssertionError("Failed to create user: " + output);
-        }
-    }
-
-    private static void removeUserOnDevice(ITestDevice device, int userId)
-            throws DeviceNotAvailableException {
-        // TODO: move this to ITestDevice once it supports users
-        final String output = device.executeShellCommand("pm remove-user " + userId);
-        if (output.startsWith("Error")) {
-            throw new AssertionError("Failed to remove user: " + output);
-        }
-    }
-
-}
diff --git a/hostsidetests/appsecurity/test-apps/Android.mk b/hostsidetests/appsecurity/test-apps/Android.mk
index f6091e4..ae48006 100644
--- a/hostsidetests/appsecurity/test-apps/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/Android.mk
@@ -16,6 +16,9 @@
 
 include $(CLEAR_VARS)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
 
diff --git a/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk b/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
index 4459e69..47323a3 100644
--- a/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsAppAccessData
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # although not strictly necessary, sign this app with different cert than CtsAppWithData
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java b/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
index 40d3cff..ba27114 100644
--- a/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
+++ b/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
@@ -18,17 +18,20 @@
 
 import java.io.BufferedReader;
 import java.io.DataInputStream;
+import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
 
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.test.AndroidTestCase;
 
 /**
  * Test that another app's private data cannot be accessed, while its public data can.
  *
- * Assumes that {@link APP_WITH_DATA_PKG} has already created the private and public data.
+ * Assumes that {@link #APP_WITH_DATA_PKG} has already created the private and public data.
  */
 public class AccessPrivateDataTest extends AndroidTestCase {
 
@@ -39,12 +42,12 @@
 
     /**
      * Name of private file to access. This must match the name of the file created by
-     * {@link APP_WITH_DATA_PKG}.
+     * {@link #APP_WITH_DATA_PKG}.
      */
     private static final String PRIVATE_FILE_NAME = "private_file.txt";
     /**
      * Name of public file to access. This must match the name of the file created by
-     * {@link APP_WITH_DATA_PKG}.
+     * {@link #APP_WITH_DATA_PKG}.
      */
     private static final String PUBLIC_FILE_NAME = "public_file.txt";
 
@@ -56,20 +59,26 @@
     public void testAccessPrivateData() throws IOException {
         try {
             // construct the absolute file path to the app's private file
-            String privateFilePath = String.format("/data/data/%s/%s", APP_WITH_DATA_PKG,
-                    PRIVATE_FILE_NAME);
-            FileInputStream inputStream = new FileInputStream(privateFilePath);
+            ApplicationInfo applicationInfo = getApplicationInfo(APP_WITH_DATA_PKG);
+            File privateFile = new File(applicationInfo.dataDir, "files/" + PRIVATE_FILE_NAME);
+            FileInputStream inputStream = new FileInputStream(privateFile);
             inputStream.read();
             inputStream.close();
             fail("Was able to access another app's private data");
-        } catch (FileNotFoundException e) {
+        } catch (FileNotFoundException | SecurityException e) {
             // expected
-        } catch (SecurityException e) {
-            // also valid
         }
         accessPrivateTrafficStats();
     }
 
+    private ApplicationInfo getApplicationInfo(String packageName) {
+        try {
+            return mContext.getPackageManager().getApplicationInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalStateException("Expected package not found: " + e);
+        }
+    }
+
     /**
      * Tests that another app's public file can be accessed
      * @throws IOException
@@ -86,10 +95,10 @@
 
     private int getOtherAppUid() throws IOException, FileNotFoundException, SecurityException {
         // construct the absolute file path to the other app's public file
-        String publicFilePath = String.format("/data/data/%s/files/%s", APP_WITH_DATA_PKG,
-                PUBLIC_FILE_NAME);
-        DataInputStream inputStream = new DataInputStream(new FileInputStream(publicFilePath));
-        int otherAppUid = (int)inputStream.readInt();
+        ApplicationInfo applicationInfo = getApplicationInfo(APP_WITH_DATA_PKG);
+        File publicFile = new File(applicationInfo.dataDir, "files/" + PUBLIC_FILE_NAME);
+        DataInputStream inputStream = new DataInputStream(new FileInputStream(publicFile));
+        int otherAppUid = inputStream.readInt();
         inputStream.close();
         return otherAppUid;
     }
@@ -98,9 +107,7 @@
         int otherAppUid = -1;
         try {
             otherAppUid = getOtherAppUid();
-        } catch (FileNotFoundException e) {
-            fail("Was not able to access another app's public file: " + e);
-        } catch (SecurityException e) {
+        } catch (FileNotFoundException | SecurityException e) {
             fail("Was not able to access another app's public file: " + e);
         }
 
diff --git a/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk b/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
index 0916254..df52f08 100644
--- a/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsAppWithData
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
 LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java b/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
index e11681a..378ef42 100644
--- a/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
+++ b/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
@@ -24,8 +24,8 @@
 import android.database.sqlite.SQLiteOpenHelper;
 import android.net.TrafficStats;
 import android.test.AndroidTestCase;
-import android.util.Log;
 
+import java.io.File;
 import java.net.ServerSocket;
 import java.net.Socket;
 
@@ -97,14 +97,11 @@
         try {
             // construct the absolute file path to the app's public's file the same
             // way as the appaccessdata package will.
-            String publicFilePath = String.format("/data/data/%s/files/%s", APP_WITH_DATA_PKG,
-                    PUBLIC_FILE_NAME);
-            DataInputStream inputStream = new DataInputStream(new FileInputStream(publicFilePath));
-            int otherAppUid = (int)inputStream.readInt();
+            File publicFile = new File(mContext.getFilesDir(), PUBLIC_FILE_NAME);
+            DataInputStream inputStream = new DataInputStream(new FileInputStream(publicFile));
+            inputStream.readInt();
             inputStream.close();
-        } catch (FileNotFoundException e) {
-            fail("Was not able to access own public file: " + e);
-        } catch (SecurityException e) {
+        } catch (FileNotFoundException | SecurityException e) {
             fail("Was not able to access own public file: " + e);
         }
     }
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
index 272ef28..54c2cc2 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
@@ -26,6 +26,9 @@
 
 LOCAL_PACKAGE_NAME := CtsDocumentClient
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
 LOCAL_PROGUARD_ENABLED := disabled
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index f308211..c2c4345 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -25,6 +25,7 @@
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsProvider;
+import android.support.test.uiautomator.Configurator;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiObjectNotFoundException;
@@ -34,6 +35,7 @@
 import android.test.MoreAsserts;
 import android.text.format.DateUtils;
 import android.util.Log;
+import android.view.MotionEvent;
 
 import com.android.cts.documentclient.MyActivity.Result;
 
@@ -59,6 +61,8 @@
     public void setUp() throws Exception {
         super.setUp();
 
+        Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
+
         mDevice = UiDevice.getInstance(getInstrumentation());
         mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
                 MyActivity.class, null);
@@ -134,15 +138,24 @@
         assertTrue("CtsCreate root", findRoot("CtsCreate").exists());
         assertFalse("CtsGetContent root", findRoot("CtsGetContent").exists());
 
-        // Pick a specific file from our test provider
+        // Choose the local root.
         mDevice.waitForIdle();
         findRoot("CtsLocal").click();
 
+        // Try picking a virtual file. Virtual files must not be returned for CATEGORY_OPENABLE
+        // though, so the click should be ignored.
+        mDevice.waitForIdle();
+        findDocument("VIRTUAL_FILE").click();
+        mDevice.waitForIdle();
+
+        // Pick a regular file.
         mDevice.waitForIdle();
         findDocument("FILE1").click();
 
+        // Confirm that the returned file is a regular file caused by the second click.
         final Result result = mActivity.getResult();
         final Uri uri = result.data.getData();
+        assertEquals("doc:file1", DocumentsContract.getDocumentId(uri));
 
         // We should now have permission to read/write
         MoreAsserts.assertEquals("fileone".getBytes(), readFully(uri));
@@ -152,6 +165,26 @@
         MoreAsserts.assertEquals("replaced!".getBytes(), readFully(uri));
     }
 
+    public void testOpenVirtual() throws Exception {
+        if (!supportedHardware()) return;
+
+        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+        intent.setType("*/*");
+        mActivity.startActivityForResult(intent, 42);
+
+        // Pick a virtual file from the local root.
+        mDevice.waitForIdle();
+        findRoot("CtsLocal").click();
+
+        mDevice.waitForIdle();
+        findDocument("VIRTUAL_FILE").click();
+
+        // Confirm that the returned file is actually the selected one.
+        final Result result = mActivity.getResult();
+        final Uri uri = result.data.getData();
+        assertEquals("virtual-file", DocumentsContract.getDocumentId(uri));
+    }
+
     public void testCreateNew() throws Exception {
         if (!supportedHardware()) return;
 
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
index bbf7734..84a1665 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
@@ -26,6 +26,9 @@
 
 LOCAL_PACKAGE_NAME := CtsDocumentProvider
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
 LOCAL_PROGUARD_ENABLED := disabled
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java b/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
index 9d38a94..ab7696f 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
@@ -124,6 +124,13 @@
             mCreateRoot.children.add(file2);
         }
 
+        {
+            Doc virtualFile = buildDoc("doc:virtual-file", "VIRTUAL_FILE", "application/icecream");
+            virtualFile.flags = Document.FLAG_VIRTUAL_DOCUMENT;
+            mLocalRoot.children.add(virtualFile);
+            mCreateRoot.children.add(virtualFile);
+        }
+
         Doc dir1 = buildDoc("doc:dir1", "DIR1", Document.MIME_TYPE_DIR);
         mLocalRoot.children.add(dir1);
 
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
index a7de92a..bbe351a 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
@@ -23,6 +23,9 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_PACKAGE_NAME := CtsExternalStorageApp
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_DEX_PREOPT := false
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index 7fe0b80..4bd494d 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -149,6 +149,22 @@
         return paths;
     }
 
+    /**
+     * Return a set of several package-specific external storage paths pointing
+     * at "gift" files designed to be exchanged with the target package.
+     */
+    public static List<File> getAllPackageSpecificGiftPaths(Context context,
+            String targetPackageName) {
+        final List<File> files = getAllPackageSpecificPaths(context);
+        final List<File> targetFiles = new ArrayList<>();
+        for (File file : files) {
+            final File targetFile = new File(
+                    file.getAbsolutePath().replace(context.getPackageName(), targetPackageName));
+            targetFiles.add(new File(targetFile, targetPackageName + ".gift"));
+        }
+        return targetFiles;
+    }
+
     public static List<File> getPrimaryPackageSpecificPaths(Context context) {
         final List<File> paths = new ArrayList<File>();
         Collections.addAll(paths, context.getExternalCacheDir());
@@ -189,12 +205,6 @@
         return after;
     }
 
-    public static File buildGiftForPackage(Context context, String packageName) {
-        final File myCache = context.getExternalCacheDir();
-        return new File(myCache.getAbsolutePath().replace(context.getPackageName(), packageName),
-                packageName + ".gift");
-    }
-
     public static File buildProbeFile(File dir) {
         return new File(dir, ".probe_" + System.nanoTime());
     }
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java
index e482b2f..14a0180 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java
@@ -21,26 +21,33 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileNoAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildGiftForPackage;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificGiftPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
 
 import android.test.AndroidTestCase;
 
 import java.io.File;
+import java.util.List;
 
 public class GiftTest extends AndroidTestCase {
     /**
      * Verify we can read only our gifts.
      */
     public void testGifts() throws Exception {
-        final File none = buildGiftForPackage(getContext(), PACKAGE_NONE);
-        assertFileReadWriteAccess(none);
-        assertEquals(100, readInt(none));
+        final List<File> noneList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_NONE);
+        for (File none : noneList) {
+            assertFileReadWriteAccess(none);
+            assertEquals(100, readInt(none));
+        }
 
-        final File read = buildGiftForPackage(getContext(), PACKAGE_READ);
-        assertFileNoAccess(read);
+        final List<File> readList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_READ);
+        for (File read : readList) {
+            assertFileNoAccess(read);
+        }
 
-        final File write = buildGiftForPackage(getContext(), PACKAGE_WRITE);
-        assertFileNoAccess(write);
+        final List<File> writeList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_WRITE);
+        for (File write : writeList) {
+            assertFileNoAccess(write);
+        }
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
index 4c64204..717d9f9 100644
--- a/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsInstrumentationAppDiffCert
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # sign this app with different cert than CtsTargetInstrumentationApp
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
index c37d052..270dac8 100644
--- a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsMultiUserStorageApp
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_DEX_PREOPT := false
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
index 43d3547..2c67bdc 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsPermissionDeclareApp
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # sign this app with a different cert than CtsUsePermissionDiffCert
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
index 5109c99..af051a0 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsPermissionDeclareAppCompat
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # sign this app with a different cert than CtsUsePermissionDiffCert
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
index c662d39..73cb625 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsReadExternalStorageApp
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_DEX_PREOPT := false
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java
index e72be77..78bb738 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java
@@ -21,28 +21,35 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadOnlyAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildGiftForPackage;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificGiftPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
 
 import android.test.AndroidTestCase;
 
 import java.io.File;
+import java.util.List;
 
 public class ReadGiftTest extends AndroidTestCase {
     /**
      * Verify we can read all gifts.
      */
     public void testGifts() throws Exception {
-        final File none = buildGiftForPackage(getContext(), PACKAGE_NONE);
-        assertFileReadOnlyAccess(none);
-        assertEquals(100, readInt(none));
+        final List<File> noneList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_NONE);
+        for (File none : noneList) {
+            assertFileReadOnlyAccess(none);
+            assertEquals(100, readInt(none));
+        }
 
-        final File read = buildGiftForPackage(getContext(), PACKAGE_READ);
-        assertFileReadWriteAccess(read);
-        assertEquals(101, readInt(read));
+        final List<File> readList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_READ);
+        for (File read : readList) {
+            assertFileReadWriteAccess(read);
+            assertEquals(101, readInt(read));
+        }
 
-        final File write = buildGiftForPackage(getContext(), PACKAGE_WRITE);
-        assertFileReadOnlyAccess(write);
-        assertEquals(102, readInt(write));
+        final List<File> writeList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_WRITE);
+        for (File write : writeList) {
+            assertFileReadOnlyAccess(write);
+            assertEquals(102, readInt(write));
+        }
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk b/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
index 05438ef..f1f6efe 100644
--- a/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsSharedUidInstall
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # sign this app with a different cert than CtsSharedUidInstallDiffCert
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
index eaed910..937a8aa 100644
--- a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsSharedUidInstallDiffCert
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # sign this app with a different cert than CtsSharedUidInstall
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
index 01cffdb..8ba76b6 100644
--- a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsSimpleAppInstall
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # sign this app with a different cert than CtsSimpleAppInstallDiffCert
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
index 032ef57..17707ee 100644
--- a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsSimpleAppInstallDiffCert
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # sign this app with a different cert than CtsSimpleAppInstall
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
index de46dea..3dd25da 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
@@ -27,6 +27,9 @@
 LOCAL_PACKAGE_NAME := CtsSplitApp
 LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4 v7 fr de
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
@@ -52,6 +55,9 @@
 LOCAL_PACKAGE_NAME := CtsSplitAppDiffRevision
 LOCAL_PACKAGE_SPLITS := v7
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_MANIFEST_FILE := revision/AndroidManifest.xml
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundredRevisionTwelve --replace-version
@@ -76,6 +82,9 @@
 LOCAL_PACKAGE_NAME := CtsSplitAppDiffVersion
 LOCAL_PACKAGE_SPLITS := v7
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 101 --version-name OneHundredOne --replace-version
 
@@ -99,6 +108,9 @@
 LOCAL_PACKAGE_NAME := CtsSplitAppDiffCert
 LOCAL_PACKAGE_SPLITS := v7
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundred --replace-version
 
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
index fbb7764..e6ea9cf 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
@@ -28,6 +28,9 @@
 
 LOCAL_MODULE_TAGS := tests
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 featureOf := CtsSplitApp
 featureOfApk := $(call intermediates-dir-for,APPS,$(featureOf))/package.apk
 localRStamp := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/src/R.stamp
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk
index 507b13a..9989ce3 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk
@@ -23,4 +23,7 @@
 
 LOCAL_LDLIBS += -llog
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/Android.mk
index 5053e7d..ba2da56 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/Android.mk
@@ -1 +1,15 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 include $(call all-subdir-makefiles)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
index 9faaba1..f322622 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
@@ -22,6 +22,9 @@
 
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
index 87b32aa..bbdc18b 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
@@ -22,6 +22,9 @@
 
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
index fe289e0..f10c843 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
@@ -22,6 +22,9 @@
 
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
index d66d674..fdd2129 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
@@ -22,6 +22,9 @@
 
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
index 7232324..8c58c0d 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
@@ -22,6 +22,9 @@
 
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
index f1cd994..fe60583 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
@@ -22,6 +22,9 @@
 
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
index 521f6f2..32f28db 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
@@ -22,6 +22,9 @@
 
 LOCAL_JAVA_RESOURCE_DIRS := raw
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
 
diff --git a/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk b/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
index f5ac52f..3300cc3 100644
--- a/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_PACKAGE_NAME := CtsTargetInstrumentationApp
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # sign this app with different cert than CtsInstrumentationAppDiffCert
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
index f91d0c4..0842ea3 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_PACKAGE_NAME := CtsUsePermissionApp
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
 LOCAL_PROGUARD_ENABLED := disabled
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk
index 70b4b0f..45b97c0 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_PACKAGE_NAME := CtsUsePermissionAppCompat
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
 LOCAL_PROGUARD_ENABLED := disabled
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
index 6e0d090..966aded 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
@@ -26,6 +26,9 @@
 
 LOCAL_PACKAGE_NAME := CtsUsePermissionDiffCert
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # sign this app with a different cert than CtsPermissionDeclareApp
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
index cdd77e8..53daf9a 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
@@ -23,6 +23,9 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_PACKAGE_NAME := CtsWriteExternalStorageApp
 
 LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index 3861ddf..ea6c0ea 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.writeexternalstorageapp;
 
+import static android.test.MoreAsserts.assertNotEqual;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_NONE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.TAG;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
@@ -31,7 +32,10 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.writeInt;
 
 import android.os.Environment;
+import android.os.SystemClock;
+import android.system.Os;
 import android.test.AndroidTestCase;
+import android.text.format.DateUtils;
 import android.util.Log;
 
 import com.android.cts.externalstorageapp.CommonExternalStorageTest;
@@ -297,4 +301,29 @@
             }
         }
     }
+
+    /**
+     * Verify that moving around package-specific directories causes permissions
+     * to be updated.
+     */
+    public void testMovePackageSpecificPaths() throws Exception {
+        final File before = getContext().getExternalCacheDir();
+        final File beforeFile = new File(before, "test.probe");
+        assertTrue(beforeFile.createNewFile());
+        assertEquals(Os.getuid(), Os.stat(before.getAbsolutePath()).st_uid);
+        assertEquals(Os.getuid(), Os.stat(beforeFile.getAbsolutePath()).st_uid);
+
+        final File after = new File(before.getAbsolutePath()
+                .replace(getContext().getPackageName(), "com.example.does.not.exist"));
+        after.getParentFile().mkdirs();
+
+        Os.rename(before.getAbsolutePath(), after.getAbsolutePath());
+
+        // Sit around long enough for VFS cache to expire
+        SystemClock.sleep(15 * DateUtils.SECOND_IN_MILLIS);
+
+        final File afterFile = new File(after, "test.probe");
+        assertNotEqual(Os.getuid(), Os.stat(after.getAbsolutePath()).st_uid);
+        assertNotEqual(Os.getuid(), Os.stat(afterFile.getAbsolutePath()).st_uid);
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java
index 5da42da..db3813f 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java
@@ -20,41 +20,48 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_READ;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildGiftForPackage;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificGiftPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.writeInt;
 
 import android.test.AndroidTestCase;
 
 import java.io.File;
+import java.util.List;
 
 public class WriteGiftTest extends AndroidTestCase {
     /**
      * Leave gifts for other packages in their primary external cache dirs.
      */
     public void testGifts() throws Exception {
-        final File none = buildGiftForPackage(getContext(), PACKAGE_NONE);
-        none.getParentFile().mkdirs();
-        none.createNewFile();
-        assertFileReadWriteAccess(none);
+        final List<File> noneList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_NONE);
+        for (File none : noneList) {
+            none.getParentFile().mkdirs();
+            none.createNewFile();
+            assertFileReadWriteAccess(none);
 
-        writeInt(none, 100);
-        assertEquals(100, readInt(none));
+            writeInt(none, 100);
+            assertEquals(100, readInt(none));
+        }
 
-        final File read = buildGiftForPackage(getContext(), PACKAGE_READ);
-        read.getParentFile().mkdirs();
-        read.createNewFile();
-        assertFileReadWriteAccess(read);
+        final List<File> readList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_READ);
+        for (File read : readList) {
+            read.getParentFile().mkdirs();
+            read.createNewFile();
+            assertFileReadWriteAccess(read);
 
-        writeInt(read, 101);
-        assertEquals(101, readInt(read));
+            writeInt(read, 101);
+            assertEquals(101, readInt(read));
+        }
 
-        final File write = buildGiftForPackage(getContext(), PACKAGE_WRITE);
-        write.getParentFile().mkdirs();
-        write.createNewFile();
-        assertFileReadWriteAccess(write);
+        final List<File> writeList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_WRITE);
+        for (File write : writeList) {
+            write.getParentFile().mkdirs();
+            write.createNewFile();
+            assertFileReadWriteAccess(write);
 
-        writeInt(write, 102);
-        assertEquals(102, readInt(write));
+            writeInt(write, 102);
+            assertEquals(102, readInt(write));
+        }
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/keysets/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/Android.mk
index 935fa95..7193868 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/Android.mk
@@ -16,6 +16,9 @@
 
 include $(CLEAR_VARS)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
 
diff --git a/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk
index 207160f..f1cf063 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk
@@ -17,6 +17,9 @@
 #apks signed cts-keyset-test-a
 include $(CLEAR_VARS)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk
index 84f3f75..ed8fdb8 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk
@@ -17,6 +17,9 @@
 #apks signed cts-keyset-test-a
 include $(CLEAR_VARS)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk
index 7290f06..d539925 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk
@@ -17,6 +17,9 @@
 #apks signed cts-keyset-test-a
 include $(CLEAR_VARS)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
index f5a7286..6f60a7a 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
@@ -23,6 +23,8 @@
 LOCAL_PACKAGE_NAME := CtsKeySetPermDefSigningA
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
@@ -35,5 +37,7 @@
 LOCAL_PACKAGE_NAME := CtsKeySetPermDefSigningB
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
index 678d89d..e9db2a8 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
@@ -24,6 +24,9 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed cts-keyset-test-b
@@ -36,4 +39,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
index b8acc99..d8f43f7 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
@@ -16,6 +16,9 @@
 
 include $(CLEAR_VARS)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
index 79d053b..7f00bb3 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
@@ -16,13 +16,14 @@
 
 #apks signed by cts-keyset-test-a
 include $(CLEAR_VARS)
-
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 LOCAL_PACKAGE_NAME := CtsKeySetSigningAUpgradeA
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
@@ -34,24 +35,26 @@
 LOCAL_PACKAGE_NAME := CtsKeySetSigningBUpgradeA
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed by cts-keyset-test-ec-a
 include $(CLEAR_VARS)
-
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 LOCAL_PACKAGE_NAME := CtsKeySetSigningEcAUpgradeA
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-ec-a
 LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed by cts-keyset-test-a and cts-keyset-test-b
 include $(CLEAR_VARS)
-
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
@@ -59,4 +62,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_ADDITIONAL_CERTIFICATES := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
index 406529c..6b27445 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
@@ -17,6 +17,9 @@
 #apks signed cts-keyset-test-a
 include $(CLEAR_VARS)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
index 23d6b17..b6b230c 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
@@ -17,6 +17,9 @@
 #apks signed cts-keyset-test-a
 include $(CLEAR_VARS)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
index f2cedf9..cb1a6a0 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
@@ -24,6 +24,9 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed cts-keyset-test-b
@@ -36,6 +39,9 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed by cts-keyset-test-a and cts-keyset-test-c
@@ -49,4 +55,7 @@
 LOCAL_ADDITIONAL_CERTIFICATES := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-c
 LOCAL_DEX_PREOPT := false
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk
index 1d6d5a5..5e56d12 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk
@@ -24,6 +24,9 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
 LOCAL_DEX_PREOPT := false
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
 
 #apks signed cts-keyset-test-b
@@ -36,4 +39,7 @@
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
 LOCAL_DEX_PREOPT := false
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
index 3d0109a..ddc0012 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
@@ -17,6 +17,9 @@
 #apks signed by cts-keyset-test-a
 include $(CLEAR_VARS)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
index 9b327fe..4e383de 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
@@ -17,6 +17,9 @@
 #apks signed cts-keyset-test-a
 include $(CLEAR_VARS)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/atrace/Android.mk b/hostsidetests/atrace/Android.mk
index 1fd7102..e2dbaba 100644
--- a/hostsidetests/atrace/Android.mk
+++ b/hostsidetests/atrace/Android.mk
@@ -21,10 +21,15 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsAtraceHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
 
 LOCAL_CTS_TEST_PACKAGE := android.host.atrace
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/atrace/AndroidTest.xml b/hostsidetests/atrace/AndroidTest.xml
new file mode 100644
index 0000000..b8aeb31
--- /dev/null
+++ b/hostsidetests/atrace/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS atrace host test cases">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsAtraceHostTestCases.jar" />
+    </test>
+</configuration>
diff --git a/hostsidetests/atrace/AtraceTestApp/Android.mk b/hostsidetests/atrace/AtraceTestApp/Android.mk
index 0eb7cfd..bbb79ee 100644
--- a/hostsidetests/atrace/AtraceTestApp/Android.mk
+++ b/hostsidetests/atrace/AtraceTestApp/Android.mk
@@ -30,4 +30,7 @@
 
 #LOCAL_DEX_PREOPT := false
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index 760723e..5f5ebe1 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -16,7 +16,7 @@
 
 package android.atrace.cts;
 
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
@@ -118,14 +118,14 @@
         }
     }
 
-    private CtsBuildHelper mCtsBuild;
+    private IBuildInfo mCtsBuild;
 
     /**
      * {@inheritDoc}
      */
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+        mCtsBuild = buildInfo;
     }
 
     // Collection of all userspace tags, and 'sched'
@@ -201,7 +201,7 @@
             getDevice().uninstallPackage(TEST_PKG);
 
             // install the test app
-            File testAppFile = mCtsBuild.getTestApp(TEST_APK);
+            File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
             String installResult = getDevice().installPackage(testAppFile, false);
             assertNull(
                     String.format("failed to install atrace test app. Reason: %s", installResult),
diff --git a/hostsidetests/devicepolicy/Android.mk b/hostsidetests/devicepolicy/Android.mk
index dc5e117..ad0d6e1 100644
--- a/hostsidetests/devicepolicy/Android.mk
+++ b/hostsidetests/devicepolicy/Android.mk
@@ -22,11 +22,14 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt tools-common-prebuilt cts-tradefed
+LOCAL_JAVA_LIBRARIES := tradefed-prebuilt tools-common-prebuilt cts-tradefed_v2
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
 
 LOCAL_CTS_TEST_PACKAGE := android.adminhostside
 
-cts_runtime_hint := 70
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/devicepolicy/AndroidTest.xml b/hostsidetests/devicepolicy/AndroidTest.xml
new file mode 100644
index 0000000..48b3b5b
--- /dev/null
+++ b/hostsidetests/devicepolicy/AndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for the CTS Device Policy host tests">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsDevicePolicyManagerTestCases.jar" />
+        <option name="runtime-hint" value="31m41s" />
+    </test>
+</configuration>
diff --git a/hostsidetests/devicepolicy/app/CertInstaller/Android.mk b/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
index 22a78e2..6ef29a5 100644
--- a/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
+++ b/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
@@ -28,4 +28,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.mk
index 0548af6..e1f1a89 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index 314f996..d75e632 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -26,8 +26,11 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util_v2
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
index 27fd36f..b2848cd 100755
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
@@ -77,17 +77,23 @@
         super.tearDown();
     }
 
-    public void testCanInstallValidRsaKeypair()
+    public void testCanInstallAndRemoveValidRsaKeypair()
             throws CertificateException, NoSuchAlgorithmException, InvalidKeySpecException,
                     KeyChainException, InterruptedException, UnsupportedEncodingException {
         final String alias = "com.android.test.valid-rsa-key-1";
         final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey , "RSA");
         final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate);
+
+        // Install key
         assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, cert, alias));
 
+        // Request and retrieve by alias
         assertEquals(alias, new KeyChainAliasFuture(alias).get());
-        final PrivateKey retrievedKey = KeyChain.getPrivateKey(getActivity(), alias);
-        assertEquals(retrievedKey.getAlgorithm(), "RSA");
+        assertEquals(KeyChain.getPrivateKey(getActivity(), alias).getAlgorithm(), "RSA");
+
+        // Delete again
+        assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias));
+        assertNull(KeyChain.getPrivateKey(getActivity(), alias));
     }
 
     public void testNullKeyParamsFailPredictably()
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk b/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk
index 98cdf52..bb9a819 100644
--- a/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/IntentSender/Android.mk b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
index e5246c5..9bb1933 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/Android.mk
+++ b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
index 5f645b6..24b5c39 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
index 2465ef3..2254e39 100644
--- a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
@@ -28,4 +28,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
index b31e74b..229cead 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
@@ -26,9 +26,12 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
-LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner compatibility-device-util_v2 \
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner compatibility-device-util \
 	ub-uiautomator
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileWidgetTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileWidgetTest.java
index 085d56f..c122b07 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileWidgetTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileWidgetTest.java
@@ -68,9 +68,8 @@
         List<String> providers = mDevicePolicyManager.getCrossProfileWidgetProviders(
                 ADMIN_RECEIVER_COMPONENT);
         assertTrue(providers.isEmpty());
-        // check that widget can still be found inside the profile
-        // This does not currently work correctly: http://b/issues/21180997
-        // assertTrue(containsWidgetProviderPkg(mAppWidgetManager.getInstalledProviders()));
+        // Check that widget can still be found inside the profile
+        assertTrue(containsWidgetProviderPkg(mAppWidgetManager.getInstalledProviders()));
     }
 
     private boolean containsWidgetProviderPkg(List<AppWidgetProviderInfo> widgets) {
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
index e68c884..ecf9837 100644
--- a/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/Android.mk b/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
index eae0a4f..744c30d 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
@@ -24,8 +24,14 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_PACKAGE_NAME := CtsSimpleApp
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk b/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
index 7460552..a6dd2c9 100644
--- a/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := 21
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk b/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
index c0e35fa..6890544 100644
--- a/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
+++ b/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
@@ -26,4 +26,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk b/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
index 47db44e..5aa11b4 100644
--- a/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
+++ b/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
@@ -26,8 +26,11 @@
 
 LOCAL_PACKAGE_NAME := CtsWifiConfigCreator
 
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util_v2
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util
 
 LOCAL_SDK_VERSION := current
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 4fc14e4..3d6a388 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.devicepolicy;
 
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.InstrumentationResultParser;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -35,8 +35,11 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.annotation.Nullable;
 
@@ -48,15 +51,20 @@
 
     private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
 
-    protected CtsBuildHelper mCtsBuild;
+    static final int USER_SYSTEM = 0; // From the UserHandle class.
+
+    private static final int FLAG_PRIMARY = 1; // From the UserInfo class
+
+    protected IBuildInfo mCtsBuild;
 
     private String mPackageVerifier;
     private HashSet<String> mAvailableFeatures;
     protected boolean mHasFeature;
+    private ArrayList<Integer> mOriginalUsers;
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+        mCtsBuild = buildInfo;
     }
 
     @Override
@@ -69,6 +77,7 @@
         mPackageVerifier = getDevice().executeShellCommand(
                 "settings get global package_verifier_enable");
         getDevice().executeShellCommand("settings put global package_verifier_enable 0");
+        mOriginalUsers = listUsers();
     }
 
     @Override
@@ -82,7 +91,8 @@
     protected void installApp(String fileName)
             throws FileNotFoundException, DeviceNotAvailableException {
         CLog.logAndDisplay(LogLevel.INFO, "Installing app " + fileName);
-        String installResult = getDevice().installPackage(mCtsBuild.getTestApp(fileName), true);
+        String installResult = getDevice().installPackage(
+            MigrationHelper.getTestFile(mCtsBuild, fileName), true);
         assertNull(String.format("Failed to install %s, Reason: %s", fileName, installResult),
                 installResult);
     }
@@ -91,7 +101,7 @@
             DeviceNotAvailableException {
         final ITestDevice device = getDevice();
 
-        final File apk = mCtsBuild.getTestApp(appFileName);
+        final File apk = MigrationHelper.getTestFile(mCtsBuild, appFileName);
         final String remotePath = "/data/local/tmp/" + apk.getName();
         if (!device.pushFile(apk, remotePath)) {
             throw new IllegalStateException("Failed to push " + apk);
@@ -112,6 +122,13 @@
                 commandOutput.startsWith("Success:"));
     }
 
+    protected void switchUser(int userId) throws Exception {
+        String command = "am switch-user " + userId;
+        CLog.logAndDisplay(LogLevel.INFO, "Starting command " + command);
+        String commandOutput = getDevice().executeShellCommand(command);
+        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+    }
+
     protected int getMaxNumberOfUsersSupported() throws DeviceNotAvailableException {
         // TODO: move this to ITestDevice once it supports users
         String command = "pm get-max-users";
@@ -126,6 +143,28 @@
         return 0;
     }
 
+    protected int getUserFlags(int userId) throws DeviceNotAvailableException {
+        String command = "pm list users";
+        String commandOutput = getDevice().executeShellCommand(command);
+        CLog.i("Output for command " + command + ": " + commandOutput);
+
+        String[] lines = commandOutput.split("\\r?\\n");
+        assertTrue(commandOutput + " should contain at least one line", lines.length >= 1);
+        for (int i = 1; i < lines.length; i++) {
+            // Individual user is printed out like this:
+            // \tUserInfo{$id$:$name$:$Integer.toHexString(flags)$} [running]
+            String[] tokens = lines[i].split("\\{|\\}|:");
+            assertTrue(lines[i] + " doesn't contain 4 or 5 tokens",
+                    tokens.length == 4 || tokens.length == 5);
+            // If the user IDs match, return the flags.
+            if (Integer.parseInt(tokens[1]) == userId) {
+                return Integer.parseInt(tokens[3], 16);
+            }
+        }
+        fail("User not found");
+        return 0;
+    }
+
     protected ArrayList<Integer> listUsers() throws DeviceNotAvailableException {
         String command = "pm list users";
         String commandOutput = getDevice().executeShellCommand(command);
@@ -148,11 +187,15 @@
         return users;
     }
 
-    protected void removeUser(int userId) throws Exception  {
+    protected void stopUser(int userId) throws Exception  {
         String stopUserCommand = "am stop-user -w " + userId;
         CLog.logAndDisplay(LogLevel.INFO, "starting command \"" + stopUserCommand + "\" and waiting.");
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + stopUserCommand + ": "
                 + getDevice().executeShellCommand(stopUserCommand));
+    }
+
+    protected void removeUser(int userId) throws Exception  {
+        stopUser(userId);
         String removeUserCommand = "pm remove-user " + userId;
         CLog.logAndDisplay(LogLevel.INFO, "starting command " + removeUserCommand);
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + removeUserCommand + ": "
@@ -161,7 +204,7 @@
 
     protected void removeTestUsers() throws Exception {
         for (int userId : listUsers()) {
-            if (userId != 0) {
+            if (!mOriginalUsers.contains(userId)) {
                 removeUser(userId);
             }
         }
@@ -207,6 +250,30 @@
         return !runResult.hasFailedTests() && runResult.getNumTestsInState(TestStatus.PASSED) > 0;
     }
 
+    /** Returns true if the system supports the split between system and primary user. */
+    protected boolean hasUserSplit() throws DeviceNotAvailableException {
+        return getBooleanSystemProperty("ro.fw.system_user_split", false);
+    }
+
+    /** Returns a boolean value of the system property with the specified key. */
+    protected boolean getBooleanSystemProperty(String key, boolean defaultValue)
+            throws DeviceNotAvailableException {
+        final String[] positiveValues = {"1", "y", "yes", "true", "on"};
+        final String[] negativeValues = {"0", "n", "no", "false", "off"};
+        String propertyValue = getDevice().getProperty(key);
+        if (propertyValue == null || propertyValue.isEmpty()) {
+            return defaultValue;
+        }
+        if (Arrays.asList(positiveValues).contains(propertyValue)) {
+            return true;
+        }
+        if (Arrays.asList(negativeValues).contains(propertyValue)) {
+            return false;
+        }
+        fail("Unexpected value of boolean system property '" + key + "': " + propertyValue);
+        return false;
+    }
+
     /** Helper method to run tests and return the listener that collected the results. */
     private TestRunResult doRunTests(
             String pkgName, String testClassName,
@@ -286,7 +353,12 @@
     }
 
     protected int createUser() throws Exception {
-        String command ="pm create-user TestUser_"+ System.currentTimeMillis();
+        return createUser(false);
+    }
+
+    protected int createUser(boolean ephemeral) throws Exception {
+        String command ="pm create-user " + (ephemeral ? "--ephemeral " : "")
+                + "TestUser_" + System.currentTimeMillis();
         CLog.logAndDisplay(LogLevel.INFO, "Starting command " + command);
         String commandOutput = getDevice().executeShellCommand(command);
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
@@ -298,9 +370,9 @@
         return Integer.parseInt(tokens[tokens.length-1]);
     }
 
-    protected int createManagedProfile() throws DeviceNotAvailableException {
-        String command =
-                "pm create-user --profileOf 0 --managed TestProfile_" + System.currentTimeMillis();
+    protected int createManagedProfile(int parentUserId) throws DeviceNotAvailableException {
+        String command = "pm create-user --profileOf " + parentUserId + " --managed "
+                + "TestProfile_" + System.currentTimeMillis();
         CLog.logAndDisplay(LogLevel.INFO, "Starting command " + command);
         String commandOutput = getDevice().executeShellCommand(command);
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
@@ -313,6 +385,26 @@
         return Integer.parseInt(tokens[tokens.length-1]);
     }
 
+    // TODO: use the method from Device.java once it is available.
+    protected int getPrimaryUser() throws DeviceNotAvailableException {
+        final String command = "pm list users";
+        final String commandOutput = getDevice().executeShellCommand(command);
+        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+        final String[] lines = commandOutput.split("\\n");
+        final Pattern p = Pattern.compile("\\{(\\d+):.*:(\\d+)");
+        for (String line : lines) {
+            Matcher m = p.matcher(line);
+            if (m.find()) {
+                final int flag = Integer.parseInt(m.group(2));
+                if ((flag & FLAG_PRIMARY) != 0) {
+                    return Integer.parseInt(m.group(1));
+                }
+            }
+        }
+        fail("There is no primary user on this device?");
+        return -1;
+    }
+
     protected int getUserSerialNumber(int userId) throws DeviceNotAvailableException{
         // dumpsys user return lines like "UserInfo{0:Owner:13} serialNo=0"
         String commandOutput = getDevice().executeShellCommand("dumpsys user");
@@ -348,8 +440,9 @@
         }
     }
 
-    protected void setDeviceAdmin(String componentName) throws DeviceNotAvailableException {
-        String command = "dpm set-active-admin '" + componentName + "'";
+    protected void setDeviceAdmin(String componentName, int userId)
+            throws DeviceNotAvailableException {
+        String command = "dpm set-active-admin --user " + userId + " '" + componentName + "'";
         String commandOutput = getDevice().executeShellCommand(command);
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
         assertTrue(commandOutput + " expected to start with \"Success:\"",
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index 8d22638..7602802 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.devicepolicy;
 
+import com.android.cts.migration.MigrationHelper;
+
 import java.io.File;
 import java.lang.Exception;
 
@@ -132,7 +134,7 @@
         if (!mHasFeature) {
             return;
         }
-        final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
+        final File apk = MigrationHelper.getTestFile(mCtsBuild, TEST_APP_APK);
         try {
             // Install the test and prepare the test apk.
             installApp(PACKAGE_INSTALLER_APK);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 43e6730..a936408 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.devicepolicy;
 
+import com.android.cts.migration.MigrationHelper;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
@@ -196,24 +197,25 @@
         if (!mHasFeature) {
             return;
         }
+        int parentUserId = getPrimaryUser();
         installAppAsUser(CERT_INSTALLER_APK, mUserId);
-        installAppAsUser(DEVICE_ADMIN_APK, USER_OWNER);
-        setDeviceAdmin(DEVICE_ADMIN_PKG + "/.PrimaryUserDeviceAdmin");
+        installAppAsUser(DEVICE_ADMIN_APK, parentUserId);
+        setDeviceAdmin(DEVICE_ADMIN_PKG + "/.PrimaryUserDeviceAdmin", parentUserId);
 
         final String adminHelperClass = ".PrimaryUserAdminHelper";
         try {
             // Set a non-empty device lockscreen password, which is a precondition for installing
             // private key pairs.
             assertTrue("Set lockscreen password failed", runDeviceTestsAsUser(DEVICE_ADMIN_PKG,
-                    adminHelperClass, "testSetPassword", 0 /* user 0 */));
+                    adminHelperClass, "testSetPassword", parentUserId));
             assertTrue("DelegatedCertInstaller failed", runDeviceTestsAsUser(DEVICE_ADMIN_PKG,
                     ".DelegatedCertInstallerTest", mUserId));
         } finally {
             // Reset lockscreen password and remove device admin.
             assertTrue("Clear lockscreen password failed", runDeviceTestsAsUser(DEVICE_ADMIN_PKG,
-                    adminHelperClass, "testClearPassword", 0 /* user 0 */));
+                    adminHelperClass, "testClearPassword", parentUserId));
             assertTrue("Clear device admin failed", runDeviceTestsAsUser(DEVICE_ADMIN_PKG,
-                    adminHelperClass, "testClearDeviceAdmin", 0 /* user 0 */));
+                    adminHelperClass, "testClearDeviceAdmin", parentUserId));
         }
     }
 
@@ -222,7 +224,7 @@
         final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
         final String UNKNOWN_SOURCES_SETTING = "install_non_market_apps";
         final String SECURE_SETTING_CATEGORY = "secure";
-        final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
+        final File apk = MigrationHelper.getTestFile(mCtsBuild, TEST_APP_APK);
         String unknownSourceSetting = null;
         try {
             // Install the test and prepare the test apk.
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java
new file mode 100644
index 0000000..cb7e67b
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 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.devicepolicy;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+
+/**
+ * Tests for emphemeral users and profiles.
+ */
+public class EphemeralUserTest extends BaseDevicePolicyTest {
+
+    private static final int FLAG_EPHEMERAL = 0x00000100;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mHasFeature = getDevice().getApiLevel() >= 24 /* Build.VERSION_CODES.N */
+                && canCreateUsers(1);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        removeTestUsers();
+        super.tearDown();
+    }
+
+    /** The user should have the ephemeral flag set if it was created as ephemeral. */
+    public void testCreateEphemeralUser() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        int userId = createUser(true);
+        int flags = getUserFlags(userId);
+        assertTrue("ephemeral flag must be set", FLAG_EPHEMERAL == (flags & FLAG_EPHEMERAL));
+    }
+
+    /** The user should not have the ephemeral flag set if it was not created as ephemeral. */
+    public void testCreateLongLivedUser() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        int userId = createUser(false);
+        int flags = getUserFlags(userId);
+        assertTrue("ephemeral flag must not be set", 0 == (flags & FLAG_EPHEMERAL));
+    }
+
+    /**
+     * The profile should have the ephemeral flag set automatically if its parent user is
+     * ephemeral.
+     */
+    public void testProfileInheritsEphemeral() throws Exception {
+        if (!mHasFeature || !hasDeviceFeature("android.software.managed_users")
+                || !hasUserSplit() || !canCreateUsers(2)) {
+            return;
+        }
+        int userId = createUser(true);
+        int profileId = createManagedProfile(userId);
+        int flags = getUserFlags(profileId);
+        assertTrue("ephemeral flag must be set", FLAG_EPHEMERAL == (flags & FLAG_EPHEMERAL));
+    }
+
+    /**
+     * Ephemeral user should be automatically removed after it is stopped.
+     */
+    public void testRemoveEphemeralOnStop() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        int userId = createUser(true);
+        startUser(userId);
+        assertTrue("ephemeral user must exists after start", listUsers().contains(userId));
+        stopUser(userId);
+        assertFalse("ephemeral user must be removed after stop", listUsers().contains(userId));
+    }
+
+    /** Checks whether it is possible to create the desired number of users. */
+    private boolean canCreateUsers(int numberOfUsers) throws DeviceNotAvailableException {
+        return listUsers().size() + numberOfUsers <= getMaxNumberOfUsersSupported();
+    }
+
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
index 1d5dd11..8da189f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
@@ -25,13 +25,11 @@
  * apps.
  */
 public class LauncherAppsMultiUserTest extends BaseLauncherAppsTest {
-    private static final String FEATURE_LIVE_TV = "android.software.live_tv";
 
     private int mSecondaryUserId;
     private int mSecondaryUserSerialNumber;
 
     private boolean mMultiUserSupported;
-    private boolean mHasLiveTvFeature;
 
     @Override
     protected void setUp() throws Exception {
@@ -39,7 +37,6 @@
         // We need multi user to be supported in order to create a secondary user
         // and api level 21 to support LauncherApps
         mMultiUserSupported = getMaxNumberOfUsersSupported() > 1 && getDevice().getApiLevel() >= 21;
-        mHasLiveTvFeature = hasDeviceFeature(FEATURE_LIVE_TV);
 
         if (mMultiUserSupported) {
             removeTestUsers();
@@ -61,7 +58,7 @@
     }
 
     public void testGetActivitiesForNonProfileFails() throws Exception {
-        if (!mMultiUserSupported || mHasLiveTvFeature) {
+        if (!mMultiUserSupported) {
             return;
         }
         installApp(SIMPLE_APP_APK);
@@ -76,7 +73,7 @@
     }
 
     public void testNoLauncherCallbackPackageAddedSecondaryUser() throws Exception {
-        if (!mMultiUserSupported || mHasLiveTvFeature) {
+        if (!mMultiUserSupported) {
             return;
         }
         startCallbackService();
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
index bb26df1..b7ac088 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
@@ -31,6 +31,7 @@
             MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
 
     private int mProfileUserId;
+    private int mParentUserId;
     private int mProfileSerialNumber;
     private int mMainUserSerialNumber;
 
@@ -42,12 +43,13 @@
             removeTestUsers();
             installTestApps();
             // Create a managed profile
-            mProfileUserId = createManagedProfile();
+            mParentUserId = getPrimaryUser();
+            mProfileUserId = createManagedProfile(mParentUserId);
             installApp(MANAGED_PROFILE_APK);
             setProfileOwnerOrFail(MANAGED_PROFILE_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS,
                     mProfileUserId);
             mProfileSerialNumber = getUserSerialNumber(mProfileUserId);
-            mMainUserSerialNumber = getUserSerialNumber(0);
+            mMainUserSerialNumber = getUserSerialNumber(mParentUserId);
             startUser(mProfileUserId);
         }
     }
@@ -73,10 +75,10 @@
             assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
                     LAUNCHER_TESTS_CLASS,
                     "testSimpleAppInstalledForUser",
-                            0, "-e testUser " + mProfileSerialNumber));
+                            mParentUserId, "-e testUser " + mProfileSerialNumber));
             assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
                     LAUNCHER_TESTS_PKG + ".LauncherAppsTests", "testSimpleAppInstalledForUser",
-                            0, "-e testUser " + mMainUserSerialNumber));
+                            mParentUserId, "-e testUser " + mMainUserSerialNumber));
         } finally {
             getDevice().uninstallPackage(SIMPLE_APP_PKG);
         }
@@ -92,7 +94,7 @@
             assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
                     LAUNCHER_TESTS_CLASS,
                             "testPackageAddedCallbackForUser",
-                            0, "-e testUser " + mProfileSerialNumber));
+                            mParentUserId, "-e testUser " + mProfileSerialNumber));
         } finally {
             getDevice().uninstallPackage(SIMPLE_APP_PKG);
         }
@@ -109,7 +111,7 @@
             assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
                     LAUNCHER_TESTS_CLASS,
                             "testPackageRemovedCallbackForUser",
-                            0, "-e testUser " + mProfileSerialNumber));
+                            mParentUserId, "-e testUser " + mProfileSerialNumber));
         } finally {
             getDevice().uninstallPackage(SIMPLE_APP_PKG);
         }
@@ -126,7 +128,7 @@
             assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
                     LAUNCHER_TESTS_CLASS,
                             "testPackageChangedCallbackForUser",
-                            0, "-e testUser " + mProfileSerialNumber));
+                            mParentUserId, "-e testUser " + mProfileSerialNumber));
         } finally {
             getDevice().uninstallPackage(SIMPLE_APP_PKG);
         }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 6dc47e6..cc06b9f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -57,10 +57,10 @@
 
     private static final String ADD_RESTRICTION_COMMAND = "add-restriction";
 
-    private static final int USER_OWNER = 0;
+    private int mParentUserId;
 
-    // ID of the profile we'll create. This will always be a profile of USER_OWNER.
-    private int mUserId;
+    // ID of the profile we'll create. This will always be a profile of the parent.
+    private int mProfileUserId;
     private String mPackageVerifier;
 
     private boolean mHasNfcFeature;
@@ -76,18 +76,21 @@
 
         if (mHasFeature) {
             removeTestUsers();
-            mUserId = createManagedProfile();
+            mParentUserId = getPrimaryUser();
+            mProfileUserId = createManagedProfile(mParentUserId);
 
             installApp(MANAGED_PROFILE_APK);
-            setProfileOwnerOrFail(MANAGED_PROFILE_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mUserId);
-            startUser(mUserId);
+            setProfileOwnerOrFail(MANAGED_PROFILE_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS,
+                    mProfileUserId);
+            switchUser(mParentUserId);
+            startUser(mProfileUserId);
         }
     }
 
     @Override
     protected void tearDown() throws Exception {
         if (mHasFeature) {
-            removeUser(mUserId);
+            removeUser(mProfileUserId);
             getDevice().uninstallPackage(MANAGED_PROFILE_PKG);
             getDevice().uninstallPackage(INTENT_SENDER_PKG);
             getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
@@ -100,7 +103,8 @@
             return;
         }
         assertTrue(runDeviceTestsAsUser(
-                MANAGED_PROFILE_PKG, MANAGED_PROFILE_PKG + ".ManagedProfileSetupTest", mUserId));
+                MANAGED_PROFILE_PKG, MANAGED_PROFILE_PKG + ".ManagedProfileSetupTest",
+                mProfileUserId));
     }
 
     /**
@@ -110,18 +114,18 @@
         if (!mHasFeature) {
             return;
         }
-        assertTrue(listUsers().contains(mUserId));
+        assertTrue(listUsers().contains(mProfileUserId));
         assertTrue(runDeviceTestsAsUser(
-                MANAGED_PROFILE_PKG, MANAGED_PROFILE_PKG + ".WipeDataTest", mUserId));
+                MANAGED_PROFILE_PKG, MANAGED_PROFILE_PKG + ".WipeDataTest", mProfileUserId));
         // Note: the managed profile is removed by this test, which will make removeUserCommand in
         // tearDown() to complain, but that should be OK since its result is not asserted.
-        assertFalse(listUsers().contains(mUserId));
+        assertFalse(listUsers().contains(mProfileUserId));
     }
 
     public void testMaxOneManagedProfile() throws Exception {
         int newUserId = -1;
         try {
-            newUserId = createManagedProfile();
+            newUserId = createManagedProfile(mParentUserId);
         } catch (AssertionFailedError expected) {
         }
         if (newUserId > 0) {
@@ -139,16 +143,17 @@
             return;
         }
         assertTrue("WiFi config already exists and could not be removed", runDeviceTestsAsUser(
-                MANAGED_PROFILE_PKG, ".WifiTest", "testRemoveWifiNetworkIfExists", USER_OWNER));
+                MANAGED_PROFILE_PKG, ".WifiTest", "testRemoveWifiNetworkIfExists", mParentUserId));
         try {
             installApp(WIFI_CONFIG_CREATOR_APK);
             assertTrue("Failed to add WiFi config", runDeviceTestsAsUser(
-                    MANAGED_PROFILE_PKG, ".WifiTest", "testAddWifiNetwork", mUserId));
+                    MANAGED_PROFILE_PKG, ".WifiTest", "testAddWifiNetwork", mProfileUserId));
 
             // Now delete the user - should undo the effect of testAddWifiNetwork.
-            removeUser(mUserId);
+            removeUser(mProfileUserId);
             assertTrue("WiFi config not removed after deleting profile", runDeviceTestsAsUser(
-                    MANAGED_PROFILE_PKG, ".WifiTest", "testWifiNetworkDoesNotExist", USER_OWNER));
+                    MANAGED_PROFILE_PKG, ".WifiTest", "testWifiNetworkDoesNotExist",
+                    mParentUserId));
         } finally {
             getDevice().uninstallPackage(WIFI_CONFIG_CREATOR_APK);
         }
@@ -160,14 +165,14 @@
         }
         // Set up activities: ManagedProfileActivity will only be enabled in the managed profile and
         // PrimaryUserActivity only in the primary one
-        disableActivityForUser("ManagedProfileActivity", 0);
-        disableActivityForUser("PrimaryUserActivity", mUserId);
+        disableActivityForUser("ManagedProfileActivity", mParentUserId);
+        disableActivityForUser("PrimaryUserActivity", mProfileUserId);
 
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
-                MANAGED_PROFILE_PKG + ".ManagedProfileTest", mUserId));
+                MANAGED_PROFILE_PKG + ".ManagedProfileTest", mProfileUserId));
 
         // Set up filters from primary to managed profile
-        String command = "am start -W --user " + mUserId  + " " + MANAGED_PROFILE_PKG
+        String command = "am start -W --user " + mProfileUserId  + " " + MANAGED_PROFILE_PKG
                 + "/.PrimaryUserFilterSetterActivity";
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": "
               + getDevice().executeShellCommand(command));
@@ -182,32 +187,36 @@
         // Disable all pre-existing browsers in the managed profile so they don't interfere with
         // intents resolution.
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testDisableAllBrowsers", mUserId));
+                "testDisableAllBrowsers", mProfileUserId));
         installApp(INTENT_RECEIVER_APK);
         installApp(INTENT_SENDER_APK);
 
-        changeVerificationStatus(USER_OWNER, INTENT_RECEIVER_PKG, "ask");
-        changeVerificationStatus(mUserId, INTENT_RECEIVER_PKG, "ask");
+        changeVerificationStatus(mParentUserId, INTENT_RECEIVER_PKG, "ask");
+        changeVerificationStatus(mProfileUserId, INTENT_RECEIVER_PKG, "ask");
         // We should have two receivers: IntentReceiverActivity and BrowserActivity in the
         // managed profile
         assertAppLinkResult("testTwoReceivers");
 
         changeUserRestrictionForUser("allow_parent_profile_app_linking", ADD_RESTRICTION_COMMAND,
-                mUserId);
+                mProfileUserId);
         // Now we should also have one receiver in the primary user, so three receivers in total.
         assertAppLinkResult("testThreeReceivers");
 
-        changeVerificationStatus(USER_OWNER, INTENT_RECEIVER_PKG, "never");
+        changeVerificationStatus(mParentUserId, INTENT_RECEIVER_PKG, "never");
         // The primary user one has been set to never: we should only have the managed profile ones.
         assertAppLinkResult("testTwoReceivers");
 
-        changeVerificationStatus(mUserId, INTENT_RECEIVER_PKG, "never");
+        changeVerificationStatus(mProfileUserId, INTENT_RECEIVER_PKG, "never");
         // Now there's only the browser in the managed profile left
         assertAppLinkResult("testReceivedByBrowserActivityInManaged");
 
+        changeVerificationStatus(mParentUserId, INTENT_RECEIVER_PKG, "always");
+        changeVerificationStatus(mProfileUserId, INTENT_RECEIVER_PKG, "ask");
+        // We've set the receiver in the primary user to always: only this one should receive the
+        // intent.
+        assertAppLinkResult("testReceivedByAppLinkActivityInPrimary");
 
-        changeVerificationStatus(mUserId, INTENT_RECEIVER_PKG, "always");
-        changeVerificationStatus(USER_OWNER, INTENT_RECEIVER_PKG, "always");
+        changeVerificationStatus(mProfileUserId, INTENT_RECEIVER_PKG, "always");
         // We have one always in the primary user and one always in the managed profile: the managed
         // profile one should have precedence.
         assertAppLinkResult("testReceivedByAppLinkActivityInManaged");
@@ -219,7 +228,8 @@
             return;
         }
 
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".SettingsIntentsTest", mUserId));
+        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".SettingsIntentsTest",
+                mProfileUserId));
     }
 
     public void testCrossProfileContent() throws Exception {
@@ -231,17 +241,17 @@
 
         // Test from parent to managed
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testRemoveAllFilters", mUserId));
+                "testRemoveAllFilters", mProfileUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testAddManagedCanAccessParentFilters", mUserId));
-        assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".ContentTest", 0));
+                "testAddManagedCanAccessParentFilters", mProfileUserId));
+        assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".ContentTest", mParentUserId));
 
         // Test from managed to parent
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testRemoveAllFilters", mUserId));
+                "testRemoveAllFilters", mProfileUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testAddParentCanAccessManagedFilters", mUserId));
-        assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".ContentTest", mUserId));
+                "testAddParentCanAccessManagedFilters", mProfileUserId));
+        assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".ContentTest", mProfileUserId));
 
     }
 
@@ -253,29 +263,29 @@
         installApp(INTENT_SENDER_APK);
 
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testAllowCrossProfileCopyPaste", mUserId));
+                "testAllowCrossProfileCopyPaste", mProfileUserId));
         // Test that managed can see what is copied in the parent.
-        testCrossProfileCopyPasteInternal(mUserId, true);
+        testCrossProfileCopyPasteInternal(mProfileUserId, true);
         // Test that the parent can see what is copied in managed.
-        testCrossProfileCopyPasteInternal(0, true);
+        testCrossProfileCopyPasteInternal(mParentUserId, true);
 
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testDisallowCrossProfileCopyPaste", mUserId));
+                "testDisallowCrossProfileCopyPaste", mProfileUserId));
         // Test that managed can still see what is copied in the parent.
-        testCrossProfileCopyPasteInternal(mUserId, true);
+        testCrossProfileCopyPasteInternal(mProfileUserId, true);
         // Test that the parent cannot see what is copied in managed.
-        testCrossProfileCopyPasteInternal(0, false);
+        testCrossProfileCopyPasteInternal(mParentUserId, false);
     }
 
     private void testCrossProfileCopyPasteInternal(int userId, boolean shouldSucceed)
             throws DeviceNotAvailableException {
-        final String direction = (userId == 0)
+        final String direction = (userId == mParentUserId)
                 ? "testAddManagedCanAccessParentFilters"
                 : "testAddParentCanAccessManagedFilters";
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testRemoveAllFilters", mUserId));
+                "testRemoveAllFilters", mProfileUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                direction, mUserId));
+                direction, mProfileUserId));
         if (shouldSucceed) {
             assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".CopyPasteTest",
                     "testCanReadAcrossProfiles", userId));
@@ -306,14 +316,14 @@
         String restriction = "no_debugging_features";  // UserManager.DISALLOW_DEBUGGING_FEATURES
 
         String addRestrictionCommandOutput =
-                changeUserRestrictionForUser(restriction, ADD_RESTRICTION_COMMAND, mUserId);
+                changeUserRestrictionForUser(restriction, ADD_RESTRICTION_COMMAND, mProfileUserId);
         assertTrue("Command was expected to succeed " + addRestrictionCommandOutput,
                 addRestrictionCommandOutput.contains("Status: ok"));
 
         // This should now fail, as the shell is not available to start activities under a different
         // user once the restriction is in place.
         addRestrictionCommandOutput =
-                changeUserRestrictionForUser(restriction, ADD_RESTRICTION_COMMAND, mUserId);
+                changeUserRestrictionForUser(restriction, ADD_RESTRICTION_COMMAND, mProfileUserId);
         assertTrue(
                 "Expected SecurityException when starting the activity "
                         + addRestrictionCommandOutput,
@@ -328,13 +338,13 @@
         }
 
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
-                "testEnableDisable", mUserId));
+                "testEnableDisable", mProfileUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
-                "testGetAddress", mUserId));
+                "testGetAddress", mProfileUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
-                "testListenUsingRfcommWithServiceRecord", mUserId));
+                "testListenUsingRfcommWithServiceRecord", mProfileUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
-                "testGetRemoteDevice", mUserId));
+                "testGetRemoteDevice", mProfileUserId));
     }
 
     public void testCameraPolicy() throws Exception {
@@ -343,43 +353,43 @@
             return;
         }
         try {
-            setDeviceAdmin(MANAGED_PROFILE_PKG + "/.PrimaryUserDeviceAdmin");
+            setDeviceAdmin(MANAGED_PROFILE_PKG + "/.PrimaryUserDeviceAdmin", mParentUserId);
 
             // Disable managed profile camera.
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testDisableCameraInManagedProfile",
-                    mUserId));
+                    mProfileUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testIsCameraEnabledInPrimaryProfile",
-                    0));
+                    mParentUserId));
 
             // Enable managed profile camera.
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testEnableCameraInManagedProfile",
-                    mUserId));
+                    mProfileUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testIsCameraEnabledInPrimaryProfile",
-                    0));
+                    mParentUserId));
 
             // Disable primary profile camera.
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testDisableCameraInPrimaryProfile",
-                    0));
+                    mParentUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testIsCameraEnabledInManagedProfile",
-                    mUserId));
+                    mProfileUserId));
 
             // Enable primary profile camera.
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testEnableCameraInPrimaryProfile",
-                    0));
+                    mParentUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testIsCameraEnabledInManagedProfile",
-                    mUserId));
+                    mProfileUserId));
         } finally {
             final String adminHelperClass = ".PrimaryUserAdminHelper";
             assertTrue("Clear device admin failed", runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
-                    adminHelperClass, "testClearDeviceAdmin", 0 /* user 0 */));
+                    adminHelperClass, "testClearDeviceAdmin", mParentUserId));
         }
     }
 
@@ -391,121 +401,136 @@
         try {
             // Insert Primary profile Contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfilePhoneAndEmailLookup_insertedAndfound", 0));
+                    "testPrimaryProfilePhoneAndEmailLookup_insertedAndfound", mParentUserId));
             // Insert Managed profile Contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfilePhoneAndEmailLookup_insertedAndfound", mUserId));
+                    "testManagedProfilePhoneAndEmailLookup_insertedAndfound", mProfileUserId));
             // Insert a primary contact with same phone & email as other enterprise contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfileDuplicatedPhoneEmailContact_insertedAndfound", 0));
+                    "testPrimaryProfileDuplicatedPhoneEmailContact_insertedAndfound",
+                    mParentUserId));
             // Insert a enterprise contact with same phone & email as other primary contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfileDuplicatedPhoneEmailContact_insertedAndfound", mUserId));
+                    "testManagedProfileDuplicatedPhoneEmailContact_insertedAndfound",
+                    mProfileUserId));
 
 
             // Set cross profile caller id to enabled
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testSetCrossProfileCallerIdDisabled_false", mUserId));
+                    "testSetCrossProfileCallerIdDisabled_false", mProfileUserId));
 
             // Primary user cannot use ordinary phone/email lookup api to access managed contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfilePhoneLookup_canNotAccessEnterpriseContact", 0));
+                    "testPrimaryProfilePhoneLookup_canNotAccessEnterpriseContact", mParentUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfileEmailLookup_canNotAccessEnterpriseContact", 0));
+                    "testPrimaryProfileEmailLookup_canNotAccessEnterpriseContact", mParentUserId));
             // Primary user can use ENTERPRISE_CONTENT_FILTER_URI to access primary contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfileEnterprisePhoneLookup_canAccessPrimaryContact", 0));
+                    "testPrimaryProfileEnterprisePhoneLookup_canAccessPrimaryContact",
+                    mParentUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfileEnterpriseEmailLookup_canAccessPrimaryContact", 0));
+                    "testPrimaryProfileEnterpriseEmailLookup_canAccessPrimaryContact",
+                    mParentUserId));
             // Primary user can use ENTERPRISE_CONTENT_FILTER_URI to access managed profile contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfileEnterprisePhoneLookup_canAccessEnterpriseContact", 0));
+                    "testPrimaryProfileEnterprisePhoneLookup_canAccessEnterpriseContact",
+                    mParentUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfileEnterpriseEmailLookup_canAccessEnterpriseContact", 0));
+                    "testPrimaryProfileEnterpriseEmailLookup_canAccessEnterpriseContact",
+                    mParentUserId));
             // When there exist contacts with the same phone/email in primary & enterprise,
             // primary user can use ENTERPRISE_CONTENT_FILTER_URI to access the primary contact.
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
                     "testPrimaryProfileEnterpriseEmailLookupDuplicated_canAccessPrimaryContact",
-                    0));
+                    mParentUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
                     "testPrimaryProfileEnterprisePhoneLookupDuplicated_canAccessPrimaryContact",
-                    0));
+                    mParentUserId));
 
             // Make sure SIP enterprise lookup works too.
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfileEnterpriseSipLookup_canAccessEnterpriseContact", 0));
+                    "testPrimaryProfileEnterpriseSipLookup_canAccessEnterpriseContact",
+                    mParentUserId));
 
             // Managed user cannot use ordinary phone/email lookup api to access primary contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfilePhoneLookup_canNotAccessPrimaryContact", mUserId));
+                    "testManagedProfilePhoneLookup_canNotAccessPrimaryContact", mProfileUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfileEmailLookup_canNotAccessPrimaryContact", mUserId));
+                    "testManagedProfileEmailLookup_canNotAccessPrimaryContact", mProfileUserId));
             // Managed user can use ENTERPRISE_CONTENT_FILTER_URI to access enterprise contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfileEnterprisePhoneLookup_canAccessEnterpriseContact", mUserId));
+                    "testManagedProfileEnterprisePhoneLookup_canAccessEnterpriseContact",
+                    mProfileUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfileEnterpriseEmailLookup_canAccessEnterpriseContact", mUserId));
+                    "testManagedProfileEnterpriseEmailLookup_canAccessEnterpriseContact",
+                    mProfileUserId));
             // Managed user cannot use ENTERPRISE_CONTENT_FILTER_URI to access primary contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfileEnterprisePhoneLookup_canNotAccessPrimaryContact", mUserId));
+                    "testManagedProfileEnterprisePhoneLookup_canNotAccessPrimaryContact",
+                    mProfileUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfileEnterpriseEmailLookup_canNotAccessPrimaryContact", mUserId));
+                    "testManagedProfileEnterpriseEmailLookup_canNotAccessPrimaryContact",
+                    mProfileUserId));
             // When there exist contacts with the same phone/email in primary & enterprise,
             // managed user can use ENTERPRISE_CONTENT_FILTER_URI to access the enterprise contact.
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
                     "testManagedProfileEnterpriseEmailLookupDuplicated_canAccessEnterpriseContact",
-                    mUserId));
+                    mProfileUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
                     "testManagedProfileEnterprisePhoneLookupDuplicated_canAccessEnterpriseContact",
-                    mUserId));
+                    mProfileUserId));
 
             // Set cross profile caller id to disabled
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testSetCrossProfileCallerIdDisabled_true", mUserId));
+                    "testSetCrossProfileCallerIdDisabled_true", mProfileUserId));
 
             // Primary user cannot use ordinary phone/email lookup api to access managed contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfilePhoneLookup_canNotAccessEnterpriseContact", 0));
+                    "testPrimaryProfilePhoneLookup_canNotAccessEnterpriseContact", mParentUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfileEmailLookup_canNotAccessEnterpriseContact", 0));
+                    "testPrimaryProfileEmailLookup_canNotAccessEnterpriseContact", mParentUserId));
             // Primary user cannot use ENTERPRISE_CONTENT_FILTER_URI to access managed contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfileEnterprisePhoneLookup_canNotAccessEnterpriseContact", 0));
+                    "testPrimaryProfileEnterprisePhoneLookup_canNotAccessEnterpriseContact",
+                    mParentUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfileEnterpriseEmailLookup_canNotAccessEnterpriseContact", 0));
+                    "testPrimaryProfileEnterpriseEmailLookup_canNotAccessEnterpriseContact",
+                    mParentUserId));
             // When there exist contacts with the same phone/email in primary & enterprise,
             // primary user can use ENTERPRISE_CONTENT_FILTER_URI to access primary contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
                     "testPrimaryProfileEnterpriseEmailLookupDuplicated_canAccessPrimaryContact",
-                    0));
+                    mParentUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
                     "testPrimaryProfileEnterprisePhoneLookupDuplicated_canAccessPrimaryContact",
-                    0));
+                    mParentUserId));
 
             // Managed user cannot use ordinary phone/email lookup api to access primary contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfilePhoneLookup_canNotAccessPrimaryContact", mUserId));
+                    "testManagedProfilePhoneLookup_canNotAccessPrimaryContact", mProfileUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfileEmailLookup_canNotAccessPrimaryContact", mUserId));
+                    "testManagedProfileEmailLookup_canNotAccessPrimaryContact", mProfileUserId));
             // Managed user cannot use ENTERPRISE_CONTENT_FILTER_URI to access primary contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfileEnterprisePhoneLookup_canNotAccessPrimaryContact", mUserId));
+                    "testManagedProfileEnterprisePhoneLookup_canNotAccessPrimaryContact",
+                    mProfileUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfileEnterpriseEmailLookup_canNotAccessPrimaryContact", mUserId));
+                    "testManagedProfileEnterpriseEmailLookup_canNotAccessPrimaryContact",
+                    mProfileUserId));
             // When there exist contacts with the same phone/email in primary & enterprise,
             // managed user can use ENTERPRISE_CONTENT_FILTER_URI to access enterprise contacts
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
                     "testManagedProfileEnterpriseEmailLookupDuplicated_canAccessEnterpriseContact",
-                    mUserId));
+                    mProfileUserId));
             assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
                     "testManagedProfileEnterprisePhoneLookupDuplicated_canAccessEnterpriseContact",
-                    mUserId));
+                    mProfileUserId));
         } finally {
             // Clean up in managed profile and primary profile
             runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testCurrentProfileContacts_removeContacts", mUserId);
+                    "testCurrentProfileContacts_removeContacts", mProfileUserId);
             runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testCurrentProfileContacts_removeContacts", 0);
+                    "testCurrentProfileContacts_removeContacts", mParentUserId);
         }
     }
 
@@ -514,7 +539,7 @@
             return;
         }
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                "testSetBluetoothContactSharingDisabled_setterAndGetter", mUserId));
+                "testSetBluetoothContactSharingDisabled_setterAndGetter", mProfileUserId));
     }
 
     public void testCannotSetProfileOwnerAgain() throws Exception {
@@ -523,11 +548,11 @@
         }
         // verify that we can't set the same admin receiver as profile owner again
         assertFalse(setProfileOwner(
-                MANAGED_PROFILE_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mUserId));
+                MANAGED_PROFILE_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mProfileUserId));
 
         // verify that we can't set a different admin receiver as profile owner
-        installAppAsUser(DEVICE_OWNER_APK, mUserId);
-        assertFalse(setProfileOwner(DEVICE_OWNER_PKG + "/" + DEVICE_OWNER_ADMIN, mUserId));
+        installAppAsUser(DEVICE_OWNER_APK, mProfileUserId);
+        assertFalse(setProfileOwner(DEVICE_OWNER_PKG + "/" + DEVICE_OWNER_ADMIN, mProfileUserId));
     }
 
     public void testCannotSetDeviceOwnerWhenProfilePresent() throws Exception {
@@ -551,22 +576,22 @@
         }
 
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
-                "testNfcShareEnabled", mUserId));
+                "testNfcShareEnabled", mProfileUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
-                "testNfcShareEnabled", 0));
+                "testNfcShareEnabled", mParentUserId));
 
         String restriction = "no_outgoing_beam";  // UserManager.DISALLOW_OUTGOING_BEAM
         String command = "add-restriction";
 
         String addRestrictionCommandOutput =
-                changeUserRestrictionForUser(restriction, command, mUserId);
+                changeUserRestrictionForUser(restriction, command, mProfileUserId);
         assertTrue("Command was expected to succeed " + addRestrictionCommandOutput,
                 addRestrictionCommandOutput.contains("Status: ok"));
 
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
-                "testNfcShareDisabled", mUserId));
+                "testNfcShareDisabled", mProfileUserId));
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
-                "testNfcShareEnabled", 0));
+                "testNfcShareEnabled", mParentUserId));
     }
 
     public void testCrossProfileWidgets() throws Exception {
@@ -576,36 +601,36 @@
 
         try {
             installApp(WIDGET_PROVIDER_APK);
-            getDevice().executeShellCommand("appwidget grantbind --user 0 --package "
-                    + WIDGET_PROVIDER_PKG);
+            getDevice().executeShellCommand("appwidget grantbind --user " + mParentUserId
+                    + " --package " + WIDGET_PROVIDER_PKG);
             startWidgetHostService();
 
             String commandOutput = changeCrossProfileWidgetForUser(WIDGET_PROVIDER_PKG,
-                    "add-cross-profile-widget", mUserId);
+                    "add-cross-profile-widget", mProfileUserId);
             assertTrue("Command was expected to succeed " + commandOutput,
                     commandOutput.contains("Status: ok"));
 
             assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetTest",
-                    "testCrossProfileWidgetProviderAdded", mUserId));
+                    "testCrossProfileWidgetProviderAdded", mProfileUserId));
             assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetPrimaryUserTest",
-                    "testHasCrossProfileWidgetProvider_true", 0));
+                    "testHasCrossProfileWidgetProvider_true", mParentUserId));
             assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetPrimaryUserTest",
-                    "testHostReceivesWidgetUpdates_true", 0));
+                    "testHostReceivesWidgetUpdates_true", mParentUserId));
 
             commandOutput = changeCrossProfileWidgetForUser(WIDGET_PROVIDER_PKG,
-                    "remove-cross-profile-widget", mUserId);
+                    "remove-cross-profile-widget", mProfileUserId);
             assertTrue("Command was expected to succeed " + commandOutput,
                     commandOutput.contains("Status: ok"));
 
             assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetTest",
-                    "testCrossProfileWidgetProviderRemoved", mUserId));
+                    "testCrossProfileWidgetProviderRemoved", mProfileUserId));
             assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetPrimaryUserTest",
-                    "testHasCrossProfileWidgetProvider_false", 0));
+                    "testHasCrossProfileWidgetProvider_false", mParentUserId));
             assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetPrimaryUserTest",
-                    "testHostReceivesWidgetUpdates_false", 0));
+                    "testHostReceivesWidgetUpdates_false", mParentUserId));
         } finally {
             changeCrossProfileWidgetForUser(WIDGET_PROVIDER_PKG, "remove-cross-profile-widget",
-                    mUserId);
+                    mProfileUserId);
             getDevice().uninstallPackage(WIDGET_PROVIDER_PKG);
         }
     }
@@ -655,15 +680,16 @@
     }
 
     protected void startWidgetHostService() throws Exception {
-        String command = "am startservice --user 0 "
-                + "-a " + WIDGET_PROVIDER_PKG + ".REGISTER_CALLBACK "
-                + "--ei user-extra " + getUserSerialNumber(mUserId)
+        String command = "am startservice --user " + mParentUserId
+                + " -a " + WIDGET_PROVIDER_PKG + ".REGISTER_CALLBACK "
+                + "--ei user-extra " + getUserSerialNumber(mProfileUserId)
                 + " " + WIDGET_PROVIDER_PKG + "/.SimpleAppWidgetHostService";
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": "
               + getDevice().executeShellCommand(command));
     }
 
     private void assertAppLinkResult(String methodName) throws DeviceNotAvailableException {
-        assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".AppLinkTest", methodName, mUserId));
+        assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".AppLinkTest", methodName,
+                mProfileUserId));
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
index bcc5bf9..0b33e8f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
@@ -28,6 +28,8 @@
  */
 public class MixedProfileOwnerTest extends DeviceAndProfileOwnerTest {
 
+    private int mParentUserId = -1;
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -37,7 +39,10 @@
 
         if (mHasFeature) {
             removeTestUsers();
-            mUserId = createManagedProfile();
+            mParentUserId = getPrimaryUser();
+            mUserId = createManagedProfile(mParentUserId);
+            switchUser(mParentUserId);
+            startUser(mUserId);
 
             installAppAsUser(DEVICE_ADMIN_APK, mUserId);
             setProfileOwnerOrFail(DEVICE_ADMIN_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mUserId);
@@ -64,9 +69,9 @@
             return;
         }
         executeDeviceTestMethod(".ScreenCaptureDisabledTest", "testSetScreenCaptureDisabled_true");
-        // start the ScreenCaptureDisabledActivity in the primary user
-        installAppAsUser(DEVICE_ADMIN_APK, USER_OWNER);
-        String command = "am start -W --user 0 " + DEVICE_ADMIN_PKG + "/"
+        // start the ScreenCaptureDisabledActivity in the parent
+        installAppAsUser(DEVICE_ADMIN_APK, mParentUserId);
+        String command = "am start -W --user " + mParentUserId + " " + DEVICE_ADMIN_PKG + "/"
                 + DEVICE_ADMIN_PKG + ".ScreenCaptureDisabledActivity";
         getDevice().executeShellCommand(command);
         executeDeviceTestMethod(".ScreenCaptureDisabledTest", "testScreenCapturePossible");
diff --git a/hostsidetests/dumpsys/Android.mk b/hostsidetests/dumpsys/Android.mk
index 5b63199..c3432cf 100644
--- a/hostsidetests/dumpsys/Android.mk
+++ b/hostsidetests/dumpsys/Android.mk
@@ -21,9 +21,14 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsDumpsysHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 tradefed-prebuilt
 
-LOCAL_CTS_TEST_PACKAGE := android.host.dumpsys
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+
+LOCAL_CTS_TEST_PACKAGE := android.dumpsys
+
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/dumpsys/AndroidTest.xml b/hostsidetests/dumpsys/AndroidTest.xml
new file mode 100644
index 0000000..f1ebc79
--- /dev/null
+++ b/hostsidetests/dumpsys/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for the CTS dumpsys host tests">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest">
+        <option name="jar" value="CtsDumpsysHostTestCases.jar" />
+    </test>
+</configuration>
diff --git a/hostsidetests/dumpsys/FramestatsTestApp/Android.mk b/hostsidetests/dumpsys/FramestatsTestApp/Android.mk
index 1104523..e13e2b4 100644
--- a/hostsidetests/dumpsys/FramestatsTestApp/Android.mk
+++ b/hostsidetests/dumpsys/FramestatsTestApp/Android.mk
@@ -25,4 +25,7 @@
 
 LOCAL_PACKAGE_NAME := CtsFramestatsTestApp
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
index 0daae03..e9b08a4 100644
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
@@ -16,7 +16,7 @@
 
 package android.dumpsys.cts;
 
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -30,7 +30,8 @@
 import java.util.Set;
 
 /**
- * Test to check the format of the dumps of various services (currently only procstats is tested).
+ * Test to check the format of the dumps of various services.
+ * Currently procstats and batterystats are tested.
  */
 public class DumpsysHostTest extends DeviceTestCase implements IBuildReceiver {
     private static final String TAG = "DumpsysHostTest";
@@ -486,6 +487,8 @@
                     case "ctr":
                         checkChargeTimeRemain(parts);
                         break;
+                    case "cpu":
+                        checkUidCpuUsage(parts);
                     default:
                         break;
                 }
@@ -515,12 +518,15 @@
 
     private void checkApk(String[] parts) {
         assertEquals(10, parts.length);
-        assertInteger(parts[4]); // wakeups
+        long wakeup_count = assertInteger(parts[4]); // wakeups
         assertNotNull(parts[5]); // apk
         assertNotNull(parts[6]); // service
         assertInteger(parts[7]); // startTime
         assertInteger(parts[8]); // starts
         assertInteger(parts[9]); // launches
+
+        // Sanity check.
+        assertTrue("wakeup count must be >= 0", wakeup_count >= 0);
     }
 
     private void checkProcess(String[] parts) {
@@ -563,13 +569,18 @@
         assertNotNull(parts[4]);      // wakelock
         assertInteger(parts[5]);      // full totalTime
         assertEquals("f", parts[6]);  // full
-        assertInteger(parts[7]);      // full count
+        long full_count = assertInteger(parts[7]);      // full count
         assertInteger(parts[8]);      // partial totalTime
         assertEquals("p", parts[9]);  // partial
-        assertInteger(parts[10]);     // partial count
+        long partial_count = assertInteger(parts[10]);     // partial count
         assertInteger(parts[11]);     // window totalTime
         assertEquals("w", parts[12]); // window
-        assertInteger(parts[13]);     // window count
+        long window_count = assertInteger(parts[13]);     // window count
+
+        // Sanity checks.
+        assertTrue("full wakelock count must be >= 0", full_count >= 0);
+        assertTrue("partial wakelock count must be >= 0", partial_count >= 0);
+        assertTrue("window wakelock count must be >= 0", window_count >= 0);
     }
 
     private void checkSync(String[] parts) {
@@ -604,16 +615,26 @@
 
     private void checkNetwork(String[] parts) {
         assertEquals(14, parts.length);
-        assertInteger(parts[4]);  // mobileBytesRx
-        assertInteger(parts[5]);  // mobileBytesTx
-        assertInteger(parts[6]);  // wifiBytesRx
-        assertInteger(parts[7]);  // wifiBytesTx
-        assertInteger(parts[8]);  // mobilePacketsRx
-        assertInteger(parts[9]);  // mobilePacketsTx
-        assertInteger(parts[10]); // wifiPacketsRx
-        assertInteger(parts[11]); // wifiPacketsTx
+        long mbRx = assertInteger(parts[4]);  // mobileBytesRx
+        long mbTx = assertInteger(parts[5]);  // mobileBytesTx
+        long wbRx = assertInteger(parts[6]);  // wifiBytesRx
+        long wbTx = assertInteger(parts[7]);  // wifiBytesTx
+        long mpRx = assertInteger(parts[8]);  // mobilePacketsRx
+        long mpTx = assertInteger(parts[9]);  // mobilePacketsTx
+        long wpRx = assertInteger(parts[10]); // wifiPacketsRx
+        long wpTx = assertInteger(parts[11]); // wifiPacketsTx
         assertInteger(parts[12]); // mobileActiveTime (usec)
         assertInteger(parts[13]); // mobileActiveCount
+
+        // Assuming each packet contains some bytes, bytes >= packets >= 0.
+        assertTrue("mobileBytesRx must be >= mobilePacketsRx", mbRx >= mpRx);
+        assertTrue("mobilePacketsRx must be >= 0", mpRx >= 0);
+        assertTrue("mobileBytesTx must be >= mobilePacketsTx", mbTx >= mpTx);
+        assertTrue("mobilePacketsTx must be >= 0", mpTx >= 0);
+        assertTrue("wifiBytesRx must be >= wifiPacketsRx", wbRx >= wpRx);
+        assertTrue("wifiPacketsRx must be >= 0", wpRx >= 0);
+        assertTrue("wifiBytesTx must be >= wifiPacketsTx", wbTx >= wpTx);
+        assertTrue("wifiPacketsTx must be >= 0", wpTx >= 0);
     }
 
     private void checkUserActivity(String[] parts) {
@@ -628,13 +649,27 @@
         if (!parts[4].equals("N/A")) {
             assertInteger(parts[4]);  // startCount
         }
-        assertInteger(parts[5]);  // batteryRealtime
-        assertInteger(parts[6]);  // batteryUptime
-        assertInteger(parts[7]);  // totalRealtime
-        assertInteger(parts[8]);  // totalUptime
+        long bReal = assertInteger(parts[5]);  // batteryRealtime
+        long bUp = assertInteger(parts[6]);  // batteryUptime
+        long tReal = assertInteger(parts[7]);  // totalRealtime
+        long tUp = assertInteger(parts[8]);  // totalUptime
         assertInteger(parts[9]);  // startClockTime
-        assertInteger(parts[10]); // batteryScreenOffRealtime
-        assertInteger(parts[11]); // batteryScreenOffUptime
+        long bOffReal = assertInteger(parts[10]); // batteryScreenOffRealtime
+        long bOffUp = assertInteger(parts[11]); // batteryScreenOffUptime
+
+        // The device cannot be up more than there are real-world seconds.
+        assertTrue("batteryRealtime must be >= batteryUptime", bReal >= bUp);
+        assertTrue("totalRealtime must be >= totalUptime", tReal >= tUp);
+        assertTrue("batteryScreenOffRealtime must be >= batteryScreenOffUptime",
+                bOffReal >= bOffUp);
+
+        // total >= battery >= battery screen-off >= 0
+        assertTrue("totalRealtime must be >= batteryRealtime", tReal >= bReal);
+        assertTrue("batteryRealtime must be >= batteryScreenOffRealtime", bReal >= bOffReal);
+        assertTrue("batteryScreenOffRealtime must be >= 0", bOffReal >= 0);
+        assertTrue("totalUptime must be >= batteryUptime", tUp >= bUp);
+        assertTrue("batteryUptime must be >= batteryScreenOffUptime", bUp >= bOffUp);
+        assertTrue("batteryScreenOffUptime must be >= 0", bOffUp >= 0);
     }
 
     private void checkBatteryDischarge(String[] parts) {
@@ -790,7 +825,11 @@
     private void checkPowerUseItem(String[] parts) {
         assertEquals(6, parts.length);
         assertNotNull(parts[4]); // label
-        assertDouble(parts[5]);  // mAh
+        double mAH = assertDouble(parts[5]);  // mAh
+
+        assertTrue("powerUseItem mAH must be >= 0", mAH >= 0);
+        // Largest current Android battery is ~5K. 100K shouldn't get made for a while.
+        assertTrue("powerUseItem mAH is expected to be <= 100000", mAH <= 100000);
     }
 
     private void checkChargeDischargeStep(String[] parts) {
@@ -814,6 +853,12 @@
         assertInteger(parts[4]); // chargeTimeRemaining
     }
 
+    private void checkUidCpuUsage(String[] parts) {
+        assertTrue(parts.length >= 6);
+        assertInteger(parts[4]); // user time
+        assertInteger(parts[5]); // system time
+    }
+
     /**
      * Tests the output of "dumpsys gfxinfo framestats".
      *
@@ -827,7 +872,7 @@
             getDevice().uninstallPackage(TEST_PKG);
 
             // install the test app
-            File testAppFile = mCtsBuild.getTestApp(TEST_APK);
+            File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
             String installResult = getDevice().installPackage(testAppFile, false);
             assertNull(
                     String.format("failed to install atrace test app. Reason: %s", installResult),
@@ -899,14 +944,14 @@
         assertTrue(foundAtLeastOneRow);
     }
 
-    private CtsBuildHelper mCtsBuild;
+    private IBuildInfo mCtsBuild;
 
     /**
      * {@inheritDoc}
      */
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+        mCtsBuild = buildInfo;
     }
 
     private static long assertInteger(String input) {
@@ -919,11 +964,12 @@
         }
     }
 
-    private static void assertDouble(String input) {
+    private static double assertDouble(String input) {
         try {
-            Double.parseDouble(input);
+            return Double.parseDouble(input);
         } catch (NumberFormatException e) {
             fail("Expected a double but found \"" + input + "\"");
+            return -1;
         }
     }
 
diff --git a/hostsidetests/jank/Android.mk b/hostsidetests/jank/Android.mk
new file mode 100644
index 0000000..0698e53
--- /dev/null
+++ b/hostsidetests/jank/Android.mk
@@ -0,0 +1,50 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := CtsJankHostTestCases
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_CTS_TEST_PACKAGE := android.jank.cts
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_DEVICE_JAR_ := CtsJankTestJar
+cts_library_jar_ := $(CTS_TESTCASES_OUT)/$(LOCAL_DEVICE_JAR_).jar
+
+$(cts_library_jar_): $(call intermediates-dir-for,JAVA_LIBRARIES,$(LOCAL_DEVICE_JAR_))/javalib.jar | $(ACP)
+	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
+	$(hide) $(ACP) -fp $< $@
+
+$(CTS_TESTCASES_OUT)/CtsJankHostTestCases.xml: $(cts_library_jar_)
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+$(COMPATIBILITY_TESTCASES_OUT_cts_v2)/CtsJankHostTestCases.jar : $(COMPATIBILITY_TESTCASES_OUT_cts_v2)/CtsOpenGlPerf2TestCases.apk
+
+# Build the library using its own makefile
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/jank/AndroidTest.xml b/hostsidetests/jank/AndroidTest.xml
new file mode 100644
index 0000000..a938678
--- /dev/null
+++ b/hostsidetests/jank/AndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Jank host test cases">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsJankHostTestCases.jar" />
+        <option name="runtime-hint" value="4m41s" />
+    </test>
+</configuration>
diff --git a/hostsidetests/jank/app/Android.mk b/hostsidetests/jank/app/Android.mk
new file mode 100644
index 0000000..13f917e
--- /dev/null
+++ b/hostsidetests/jank/app/Android.mk
@@ -0,0 +1,31 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := CtsJankTestJar
+LOCAL_DEX_PREOPT := false
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_JAVA_LIBRARIES := uiautomator.core
+
+LOCAL_STATIC_JAVA_LIBRARIES := com.android.uiautomator.platform.common
+
+include $(BUILD_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/hostsidetests/jank/app/src/android/jank/cts/CtsJankTestBase.java b/hostsidetests/jank/app/src/android/jank/cts/CtsJankTestBase.java
new file mode 100644
index 0000000..1eda12f
--- /dev/null
+++ b/hostsidetests/jank/app/src/android/jank/cts/CtsJankTestBase.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 android.jank.cts;
+
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.uiautomator.platform.JankTestBase;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Scanner;
+
+public class CtsJankTestBase extends JankTestBase {
+    private final static String TAG = CtsJankTestBase.class.getName();
+    protected final static String START_CMD = "am start -W -a android.intent.action.MAIN -n %s";
+    protected final static String STOP_CMD = "am force-stop %s";
+    protected final static String INTENT_STRING_EXTRA = " --es %s %s";
+    protected final static String INTENT_BOOLEAN_EXTRA = " --ez %s %b";
+    protected final static String INTENT_INTEGER_EXTRA = " --ei %s %d";
+    protected static long SLEEP_TIME = 2000; // 2 seconds
+    protected static int NUM_ITERATIONS = 5;
+    protected static int TRACE_TIME = 5;
+
+    @Override
+    protected String getPropertyString(Bundle params, String key)
+            throws FileNotFoundException, IOException {
+        if (key.equals("iteration")) {
+            return NUM_ITERATIONS + "";
+        }
+        if (key.equals("tracetime")) {
+            return TRACE_TIME + "";
+        }
+        return super.getPropertyString(params, key);
+    }
+
+    protected void runShellCommand(String command) throws Exception {
+        Process p = null;
+        Scanner out = null;
+        Scanner err = null;
+        try {
+            p = Runtime.getRuntime().exec(command);
+
+            StringBuilder outStr = new StringBuilder();
+            StringBuilder errStr = new StringBuilder();
+            out = new Scanner(p.getInputStream());
+            err = new Scanner(p.getErrorStream());
+            boolean read = true;
+            while (read) {
+                if (out.hasNextLine()) {
+                    outStr.append(out.nextLine());
+                    outStr.append("\n");
+                } else if (err.hasNextLine()) {
+                    errStr.append(err.nextLine());
+                    errStr.append("\n");
+                } else {
+                    read = false;
+                }
+            }
+            Log.i(TAG, command);
+            if (outStr.length() > 0) {
+                Log.i(TAG, outStr.toString());
+            }
+            if (errStr.length() > 0) {
+                Log.e(TAG, errStr.toString());
+            }
+        } finally {
+            if (p != null) {
+                int status = p.waitFor();
+                if (status != 0) {
+                    throw new RuntimeException(
+                            String.format("Run shell command: %s, status: %s", command, status));
+                }
+                p.destroy();
+                p = null;
+            }
+            if (out != null) {
+                out.close();
+            }
+            if (err != null) {
+                err.close();
+            }
+        }
+    }
+}
diff --git a/hostsidetests/jank/app/src/android/jank/cts/opengl/CtsDeviceJankOpenGl.java b/hostsidetests/jank/app/src/android/jank/cts/opengl/CtsDeviceJankOpenGl.java
new file mode 100755
index 0000000..46dc06c
--- /dev/null
+++ b/hostsidetests/jank/app/src/android/jank/cts/opengl/CtsDeviceJankOpenGl.java
@@ -0,0 +1,111 @@
+/*
+ * 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 android.jank.cts.opengl;
+
+import android.jank.cts.CtsJankTestBase;
+import android.util.Log;
+
+import com.android.uiautomator.platform.SurfaceFlingerHelper;
+
+public class CtsDeviceJankOpenGl extends CtsJankTestBase {
+    private final static String TAG = CtsDeviceJankOpenGl.class.getName();
+    private final static String PACKAGE = "android.opengl2.cts";
+    private final static String COMPONENT =
+            PACKAGE + "/" + PACKAGE + ".primitive.GLPrimitiveActivity";
+    private static String APP_WINDOW_NAME = "SurfaceView";
+
+    /**
+     * Runs the full OpenGL ES 2.0 pipeline test.
+     */
+    public void testFullPipeline() throws Exception {
+        runBenchmark("FullPipeline");
+    }
+
+    /**
+     * Runs the pixel output test.
+     */
+    public void testPixelOutput() throws Exception {
+        runBenchmark("PixelOutput");
+    }
+
+    /**
+     * Runs the shader performance test.
+     */
+    public void testShaderPerf() throws Exception {
+        runBenchmark("ShaderPerf");
+    }
+
+    /**
+     * Runs the context switch overhead test.
+     */
+    public void testContextSwitch() throws Exception {
+        runBenchmark("ContextSwitch");
+    }
+
+    /**
+     * Runs the benchhmark for jank test.
+     */
+    public void runBenchmark(String benchmark) throws Exception {
+        // Start activity command
+        final StringBuilder sb = new StringBuilder();
+        sb.append(String.format(START_CMD, COMPONENT));
+        sb.append(String.format(INTENT_STRING_EXTRA, "benchmark_name", benchmark));
+        sb.append(String.format(INTENT_BOOLEAN_EXTRA, "offscreen", false));
+        sb.append(String.format(INTENT_INTEGER_EXTRA, "num_frames", 1000));
+        sb.append(String.format(INTENT_INTEGER_EXTRA, "num_iterations", 1));
+        sb.append(String.format(INTENT_INTEGER_EXTRA, "timeout", 10000));
+        final String startCommand = sb.toString();
+        final String stopCommand = String.format(STOP_CMD, PACKAGE);
+
+        Log.i(TAG, "Start command: " + startCommand);
+        Log.i(TAG, "Stop command: " + stopCommand);
+
+        setIteration(NUM_ITERATIONS);
+        for (int i = 0; i < NUM_ITERATIONS; i++) {
+            // Stop any existing instances
+            runShellCommand(stopCommand);
+            // Start activity
+            runShellCommand(startCommand);
+
+            // Wait for the activity to start
+            sleep(SLEEP_TIME / 2);
+
+            // Start systrace
+            startTrace(mTestCaseName, i);
+
+            // Clear SurfaceFlinger buffer
+            Log.i(TAG, "Clearing SurfaceFlinger buffer");
+            SurfaceFlingerHelper.clearBuffer(APP_WINDOW_NAME);
+
+            // This is where user interactions would go, in this case just sleep
+            sleep(SLEEP_TIME);
+
+            // Dump SurfaceFlinger buffer
+            Log.i(TAG, "Dumping SurfaceFlinger buffer");
+            boolean result = SurfaceFlingerHelper.dumpFrameLatency(APP_WINDOW_NAME, true);
+            assertTrue("SurfaceFlingerHelper could not get timestamps", result);
+
+            // Stop systrace
+            endTrace();
+
+            // Record results
+            recordResults(mTestCaseName, i);
+        }
+        // Save aggregated results
+        saveResults(mTestCaseName);
+        // Stop any remaining instances
+        runShellCommand(stopCommand);
+    }
+}
diff --git a/hostsidetests/jank/src/android/jank/cts/CtsHostJankTest.java b/hostsidetests/jank/src/android/jank/cts/CtsHostJankTest.java
new file mode 100644
index 0000000..a33a3e4
--- /dev/null
+++ b/hostsidetests/jank/src/android/jank/cts/CtsHostJankTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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 android.jank.cts;
+
+import com.android.compatibility.common.util.MetricsReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.cts.migration.MigrationHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Scanner;
+
+public abstract class CtsHostJankTest extends TestCase
+        implements IAbiReceiver, IDeviceTest, IBuildReceiver {
+
+    private static final String TAG = CtsHostJankTest.class.getSimpleName();
+    private static final String DEVICE_LOCATION = "/data/local/tmp/";
+    // FIXME uiautomator is deprecated and does not support --abi flag
+    private static final String RUN_UI_AUTOMATOR_CMD = "uiautomator runtest %s -c %s";
+    private final String mHostTestClass;
+    private final String mDeviceTestClass;
+    private final String mJarName;
+    private final String mJarPath;
+    protected ITestDevice mDevice;
+    protected IBuildInfo mBuild;
+    protected IAbi mAbi;
+
+    public CtsHostJankTest(String jarName, String deviceTestClass, String hostTestClass) {
+        this.mHostTestClass = hostTestClass;
+        this.mDeviceTestClass = deviceTestClass;
+        this.mJarName = jarName;
+        this.mJarPath = DEVICE_LOCATION + jarName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mBuild = buildInfo;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDevice(ITestDevice device) {
+        mDevice = device;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ITestDevice getDevice() {
+        return mDevice;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDevice = getDevice();
+        // Push jar to device.
+        File jarFile = MigrationHelper.getTestFile(mBuild, mJarName);
+        boolean result = mDevice.pushFile(jarFile, mJarPath);
+        assertTrue("Failed to push file to " + mJarPath, result);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void tearDown() throws Exception {
+        // Delete jar from device.
+        mDevice.executeShellCommand("rm " + mJarPath);
+        super.tearDown();
+    }
+
+    public void runUiAutomatorTest(String testName) throws Exception {
+        // Delete any existing result files
+        mDevice.executeShellCommand("rm -r " + DEVICE_LOCATION + "*.txt");
+
+        // Run ui automator test.
+        mDevice.executeShellCommand(
+                String.format(RUN_UI_AUTOMATOR_CMD, mJarName, mDeviceTestClass + "#" + testName));
+
+        // Pull result file across
+        File result = mDevice.pullFile(DEVICE_LOCATION + "UiJankinessTestsOutput.txt");
+        assertNotNull("Couldn't get result file", result);
+        // Parse result file
+        Scanner in = new Scanner(result);
+        HashMap<String, Double> results = new HashMap<String, Double>(4);
+        while (in.hasNextLine()) {
+            String[] parts = in.nextLine().split(":");
+            if (parts.length == 2) {
+                results.put(parts[0], Double.parseDouble(parts[1]));
+            }
+        }
+        in.close();
+        assertEquals("Could not parse the results file: ", 4, results.size());
+
+        double avgNumJanks = results.get("average number of jankiness");
+        double maxNumJanks = results.get("max number of jankiness");
+        double avgFrameRate = results.get("average frame rate");
+        double avgMaxAccFrames = results.get("average of max accumulated frames");
+
+        // Create and deliver the report.
+        MetricsReportLog report = new MetricsReportLog(mDevice.getSerialNumber(), mAbi.getName(),
+                mHostTestClass + "#" + testName);
+        report.addValue(
+                "Average Frame Rate", avgFrameRate, ResultType.HIGHER_BETTER, ResultUnit.COUNT);
+        report.addValue("Average of Maximum Accumulated Frames", avgMaxAccFrames,
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        report.addValue(
+                "Maximum Number of Janks", maxNumJanks, ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        report.setSummary(
+                "Average Number of Janks", avgNumJanks, ResultType.LOWER_BETTER, ResultUnit.SCORE);
+        report.submit();
+    }
+
+}
diff --git a/hostsidetests/jank/src/android/jank/cts/opengl/CtsHostJankOpenGl.java b/hostsidetests/jank/src/android/jank/cts/opengl/CtsHostJankOpenGl.java
new file mode 100644
index 0000000..193d543
--- /dev/null
+++ b/hostsidetests/jank/src/android/jank/cts/opengl/CtsHostJankOpenGl.java
@@ -0,0 +1,68 @@
+/*
+ * 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 android.jank.cts.opengl;
+
+import android.jank.cts.CtsHostJankTest;
+
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.cts.migration.MigrationHelper;
+
+import java.io.File;
+
+public class CtsHostJankOpenGl extends CtsHostJankTest {
+
+    private static final String APK_PACKAGE = "android.opengl2.cts";
+    private static final String APK = "CtsOpenGlPerf2TestCases.apk";
+    private static final String PACKAGE = "android.jank.cts";
+    private static final String HOST_CLASS = CtsHostJankOpenGl.class.getName();
+    private static final String DEVICE_CLASS = PACKAGE + ".opengl.CtsDeviceJankOpenGl";
+    private static final String JAR_NAME = "CtsJankTestJar.jar";
+
+    public CtsHostJankOpenGl() {
+        super(JAR_NAME, DEVICE_CLASS, HOST_CLASS);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Install the app.
+        mDevice.uninstallPackage(APK_PACKAGE);
+        File app = MigrationHelper.getTestFile(mBuild, APK);
+        String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+        mDevice.installPackage(app, false, options);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        // Uninstall the app.
+        mDevice.uninstallPackage(APK_PACKAGE);
+        super.tearDown();
+    }
+
+    public void testFullPipeline() throws Exception {
+        runUiAutomatorTest("testFullPipeline");
+    }
+
+    public void testPixelOutput() throws Exception {
+        runUiAutomatorTest("testPixelOutput");
+    }
+
+    public void testShaderPerf() throws Exception {
+        runUiAutomatorTest("testShaderPerf");
+    }
+
+    public void testContextSwitch() throws Exception {
+        runUiAutomatorTest("testContextSwitch");
+    }
+}
diff --git a/hostsidetests/jdwpsecurity/Android.mk b/hostsidetests/jdwpsecurity/Android.mk
index 561d346..82d6987 100644
--- a/hostsidetests/jdwpsecurity/Android.mk
+++ b/hostsidetests/jdwpsecurity/Android.mk
@@ -23,7 +23,10 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsJdwpSecurityHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt cts-migration-lib
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 LOCAL_CTS_TEST_PACKAGE := android.host.jdwpsecurity
 
diff --git a/hostsidetests/jdwpsecurity/AndroidTest.xml b/hostsidetests/jdwpsecurity/AndroidTest.xml
new file mode 100644
index 0000000..bbb99e9
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for the CTS JDWP host test cases">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsJdwpSecurityHostTestCases.jar" />
+    </test>
+</configuration>
diff --git a/hostsidetests/jdwpsecurity/app/Android.mk b/hostsidetests/jdwpsecurity/app/Android.mk
index 13b5be4..efa7b5c 100644
--- a/hostsidetests/jdwpsecurity/app/Android.mk
+++ b/hostsidetests/jdwpsecurity/app/Android.mk
@@ -18,6 +18,8 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := CtsJdwpApp
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 include $(BUILD_JAVA_LIBRARY)
 
 # Copy the built module to the cts dir
diff --git a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
index 8e276ed..186728c 100644
--- a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
+++ b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
@@ -16,7 +16,7 @@
 
 package android.jdwpsecurity.cts;
 
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
@@ -45,7 +45,7 @@
     private static final String DEVICE_JAR_FILENAME = "CtsJdwpApp.jar";
     private static final String JAR_MAIN_CLASS_NAME = "com.android.cts.jdwpsecurity.JdwpTest";
 
-    private CtsBuildHelper mCtsBuild;
+    private IBuildInfo mBuildInfo;
 
     private static String getDeviceScriptFilepath() {
         return DEVICE_LOCATION + File.separator + DEVICE_SCRIPT_FILENAME;
@@ -57,7 +57,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+        mBuildInfo = buildInfo;
     }
 
     @Override
@@ -85,7 +85,7 @@
         getDevice().executeShellCommand("chmod 755 " + getDeviceScriptFilepath());
 
         // Push jar file.
-        File jarFile = mCtsBuild.getTestApp(DEVICE_JAR_FILENAME);
+        File jarFile = MigrationHelper.getTestFile(mBuildInfo, DEVICE_JAR_FILENAME);
         boolean success = getDevice().pushFile(jarFile, getDeviceJarFilepath());
         assertTrue("Failed to push jar file to " + getDeviceScriptFilepath(), success);
     }
diff --git a/hostsidetests/monkey/Android.mk b/hostsidetests/monkey/Android.mk
index c9f3bb3..b377996 100644
--- a/hostsidetests/monkey/Android.mk
+++ b/hostsidetests/monkey/Android.mk
@@ -22,11 +22,16 @@
 
 LOCAL_MODULE := CtsMonkeyTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
 
 # prefix zzz intentional to run this last
 LOCAL_CTS_TEST_PACKAGE := zzz.android.monkey
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/monkey/AndroidTest.xml b/hostsidetests/monkey/AndroidTest.xml
new file mode 100644
index 0000000..799ee6a
--- /dev/null
+++ b/hostsidetests/monkey/AndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for the CTS monkey host tests">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsMonkeyTestCases.jar" />
+        <option name="runtime-hint" value="5m7s" />
+    </test>
+</configuration>
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
index b31a32d..26023be 100755
--- a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
@@ -1,7 +1,7 @@
 package com.android.cts.monkey;
 
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.cts.migration.MigrationHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -23,7 +23,7 @@
     static final String MONKEY_CMD = "monkey --pct-motion 0 --pct-majornav 0 --pct-syskeys 0 --pct-anyevent 0 --pct-rotation 0";
 
     IAbi mAbi;
-    CtsBuildHelper mBuild;
+    IBuildInfo mBuild;
     ITestDevice mDevice;
 
     @Override
@@ -33,7 +33,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+        mBuild = buildInfo;
     }
 
     @Override
@@ -43,7 +43,7 @@
         String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
         for (int i = 0; i < PKGS.length; i++) {
             mDevice.uninstallPackage(PKGS[i]);
-            File app = mBuild.getTestApp(APKS[i]);
+            File app = MigrationHelper.getTestFile(mBuild, APKS[i]);
             mDevice.installPackage(app, false, options);
         }
         clearLogCat();
diff --git a/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk b/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
index c04d4b2..49288ad 100644
--- a/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
+++ b/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_DEX_PREOPT := false
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk b/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
index b3cb181..8d58435 100644
--- a/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
+++ b/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_DEX_PREOPT := false
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/net/Android.mk b/hostsidetests/net/Android.mk
index 6637d61..b4e1e3d 100644
--- a/hostsidetests/net/Android.mk
+++ b/hostsidetests/net/Android.mk
@@ -21,10 +21,15 @@
 
 LOCAL_MODULE := CtsHostsideNetworkTests
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
 
 LOCAL_CTS_TEST_PACKAGE := android.net.hostsidenetwork
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 # Build the test APKs using their own makefiles
diff --git a/hostsidetests/net/AndroidTest.xml b/hostsidetests/net/AndroidTest.xml
new file mode 100644
index 0000000..4b6994a
--- /dev/null
+++ b/hostsidetests/net/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS net host test cases">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsHostsideNetworkTests.jar" />
+    </test>
+</configuration>
diff --git a/hostsidetests/net/app/Android.mk b/hostsidetests/net/app/Android.mk
index 055287a..b64c4c9 100644
--- a/hostsidetests/net/app/Android.mk
+++ b/hostsidetests/net/app/Android.mk
@@ -29,4 +29,7 @@
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTests.java b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTests.java
index a7698f3..f42de0e 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTests.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTests.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.net;
 
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestResult;
@@ -39,7 +39,7 @@
     private static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk";
 
     private IAbi mAbi;
-    private CtsBuildHelper mCtsBuild;
+    private IBuildInfo mCtsBuild;
 
     @Override
     public void setAbi(IAbi abi) {
@@ -48,7 +48,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+        mCtsBuild = buildInfo;
     }
 
     @Override
@@ -60,7 +60,8 @@
 
         getDevice().uninstallPackage(TEST_PKG);
 
-        assertNull(getDevice().installPackage(mCtsBuild.getTestApp(TEST_APK), false));
+        assertNull(getDevice().installPackage(
+            MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false));
     }
 
     @Override
diff --git a/hostsidetests/os/Android.mk b/hostsidetests/os/Android.mk
index 6962e0c..a318622 100644
--- a/hostsidetests/os/Android.mk
+++ b/hostsidetests/os/Android.mk
@@ -27,7 +27,10 @@
 
 LOCAL_CTS_TEST_PACKAGE := android.host.os
 
-LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/$(CTS_MODULE_TEST_CONFIG)
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/os/AndroidTest.xml b/hostsidetests/os/AndroidTest.xml
index 6694c30..ff6e6b0 100644
--- a/hostsidetests/os/AndroidTest.xml
+++ b/hostsidetests/os/AndroidTest.xml
@@ -13,7 +13,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="CTS package preparer for install/uninstall of the apk used as a test operation target">
-    <include name="common-config" />
-    <option name="cts-apk-installer:test-file-name" value="CtsDeviceOsTestApp.apk" />
+<configuration description="Config for the CTS OS host test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsDeviceOsTestApp.apk" />
+    </target_preparer>
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsOsHostTestCases.jar" />
+    </test>
 </configuration>
diff --git a/hostsidetests/os/OldAndroidTest.xml b/hostsidetests/os/OldAndroidTest.xml
new file mode 100644
index 0000000..6694c30
--- /dev/null
+++ b/hostsidetests/os/OldAndroidTest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="CTS package preparer for install/uninstall of the apk used as a test operation target">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsDeviceOsTestApp.apk" />
+</configuration>
diff --git a/hostsidetests/os/app/Android.mk b/hostsidetests/os/app/Android.mk
index 46861d69..ed0c4e8 100644
--- a/hostsidetests/os/app/Android.mk
+++ b/hostsidetests/os/app/Android.mk
@@ -23,6 +23,9 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_PACKAGE_NAME := CtsDeviceOsTestApp
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/os/app/AndroidManifest.xml b/hostsidetests/os/app/AndroidManifest.xml
index 103cf63..4c4338b 100755
--- a/hostsidetests/os/app/AndroidManifest.xml
+++ b/hostsidetests/os/app/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.app.os.test">
+    package="android.os.app">
 
     <application>
         <activity android:name=".TestNonExported"
diff --git a/hostsidetests/os/app/src/android/os/app/TestNonExported.java b/hostsidetests/os/app/src/android/os/app/TestNonExported.java
new file mode 100644
index 0000000..11c41c9
--- /dev/null
+++ b/hostsidetests/os/app/src/android/os/app/TestNonExported.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 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.os.app;
+
+import android.app.Activity;
+
+/**
+ * Should never be launched: intentionally not exported
+ */
+public class TestNonExported extends Activity {
+}
diff --git a/hostsidetests/os/app/src/com/android/cts/app/os/test/TestNonExported.java b/hostsidetests/os/app/src/com/android/cts/app/os/test/TestNonExported.java
deleted file mode 100644
index c865c89..0000000
--- a/hostsidetests/os/app/src/com/android/cts/app/os/test/TestNonExported.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2015 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.app.os.test;
-
-import android.app.Activity;
-
-/**
- * Should never be launched: intentionally not exported
- */
-public class TestNonExported extends Activity {
-}
diff --git a/hostsidetests/os/src/android/os/cts/OsHostTests.java b/hostsidetests/os/src/android/os/cts/OsHostTests.java
new file mode 100644
index 0000000..73e36c5
--- /dev/null
+++ b/hostsidetests/os/src/android/os/cts/OsHostTests.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 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.os.cts;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+public class OsHostTests extends DeviceTestCase implements IBuildReceiver {
+    private static final String TEST_APP_PACKAGE = "android.os.app";
+    private static final String TEST_NON_EXPORTED_ACTIVITY_CLASS = "TestNonExported";
+
+    private static final String START_NON_EXPORTED_ACTIVITY_COMMAND = String.format(
+            "am start -n %s/%s.%s",
+            TEST_APP_PACKAGE, TEST_APP_PACKAGE, TEST_NON_EXPORTED_ACTIVITY_CLASS);
+
+    /**
+     * A reference to the device under test.
+     */
+    private ITestDevice mDevice;
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Get the device, this gives a handle to run commands and install APKs.
+        mDevice = getDevice();
+    }
+
+    /**
+     * Test whether non-exported activities are properly not launchable.
+     *
+     * @throws Exception
+     */
+    public void testNonExportedActivities() throws Exception {
+        // Attempt to launch the non-exported activity in the test app
+        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand(START_NON_EXPORTED_ACTIVITY_COMMAND, outputReceiver);
+        final String output = outputReceiver.getOutput();
+
+        assertTrue(output.contains("Permission Denial") && output.contains(" not exported"));
+    }
+}
diff --git a/hostsidetests/os/src/com/android/cts/app/os/OsHostTests.java b/hostsidetests/os/src/com/android/cts/app/os/OsHostTests.java
deleted file mode 100644
index d01a521..0000000
--- a/hostsidetests/os/src/com/android/cts/app/os/OsHostTests.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 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.app.os;
-
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.CollectingOutputReceiver;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-public class OsHostTests extends DeviceTestCase implements IBuildReceiver {
-    private static final String TEST_APP_PACKAGE = "com.android.cts.app.os.test";
-    private static final String TEST_NON_EXPORTED_ACTIVITY_CLASS = "TestNonExported";
-
-    private static final String START_NON_EXPORTED_ACTIVITY_COMMAND = String.format(
-            "am start -n %s/%s.%s",
-            TEST_APP_PACKAGE, TEST_APP_PACKAGE, TEST_NON_EXPORTED_ACTIVITY_CLASS);
-
-    /**
-     * A reference to the device under test.
-     */
-    private ITestDevice mDevice;
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        // Get the device, this gives a handle to run commands and install APKs.
-        mDevice = getDevice();
-    }
-
-    /**
-     * Test whether non-exported activities are properly not launchable.
-     *
-     * @throws Exception
-     */
-    public void testNonExportedActivities() throws Exception {
-        // Attempt to launch the non-exported activity in the test app
-        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
-        mDevice.executeShellCommand(START_NON_EXPORTED_ACTIVITY_COMMAND, outputReceiver);
-        final String output = outputReceiver.getOutput();
-
-        assertTrue(output.contains("Permission Denial") && output.contains(" not exported"));
-    }
-}
diff --git a/hostsidetests/sample/Android.mk b/hostsidetests/sample/Android.mk
index e8cbdda..8a76a8b 100644
--- a/hostsidetests/sample/Android.mk
+++ b/hostsidetests/sample/Android.mk
@@ -18,15 +18,15 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
 
-# Must match the package name in CtsTestCaseList.mk
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_MODULE := CtsSampleHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed_v2 tradefed-prebuilt
 
-LOCAL_CTS_TEST_PACKAGE := android.host.sample
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+include $(BUILD_HOST_JAVA_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/sample/AndroidTest.xml b/hostsidetests/sample/AndroidTest.xml
new file mode 100644
index 0000000..bb1c146
--- /dev/null
+++ b/hostsidetests/sample/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Sample host test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSampleDeviceApp.apk" />
+    </target_preparer>
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsSampleHostTestCases.jar" />
+    </test>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="host" />
+        <option name="module-name" value="CtsSampleHostTestCases"/>
+        <option name="version-name" value="1.0"/>
+    </target_preparer>
+</configuration>
diff --git a/hostsidetests/sample/DynamicConfig.xml b/hostsidetests/sample/DynamicConfig.xml
new file mode 100644
index 0000000..18c07ef
--- /dev/null
+++ b/hostsidetests/sample/DynamicConfig.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<DynamicConfig>
+    <Config key ="local-config">local-config-val</Config>
+</DynamicConfig>
diff --git a/hostsidetests/sample/app/Android.mk b/hostsidetests/sample/app/Android.mk
index 4af45b9..773f24f 100644
--- a/hostsidetests/sample/app/Android.mk
+++ b/hostsidetests/sample/app/Android.mk
@@ -16,16 +16,22 @@
 
 include $(CLEAR_VARS)
 
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_PACKAGE_NAME := CtsSampleDeviceApp
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_CTS_PACKAGE)
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/sample/app/AndroidManifest.xml b/hostsidetests/sample/app/AndroidManifest.xml
index c087435..dfacf25 100755
--- a/hostsidetests/sample/app/AndroidManifest.xml
+++ b/hostsidetests/sample/app/AndroidManifest.xml
@@ -18,7 +18,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.sample.app">
 
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
         <activity android:name=".SampleDeviceActivity" >
             <intent-filter>
diff --git a/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java b/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
index bed4c05..b75ea94 100644
--- a/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
+++ b/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
@@ -16,15 +16,13 @@
 
 package android.sample.cts;
 
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.tradefed.util.HostReportLog;
-import com.android.cts.util.MeasureRun;
-import com.android.cts.util.MeasureTime;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.Stat;
-import com.android.ddmlib.IDevice;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.util.MeasureRun;
+import com.android.compatibility.common.util.MeasureTime;
+import com.android.compatibility.common.util.MetricsReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -37,7 +35,6 @@
 import com.android.tradefed.util.RunUtil;
 
 import java.io.File;
-import java.lang.Exception;
 
 /**
  * Test to measure the transfer time of a file from the host to the device.
@@ -52,16 +49,21 @@
     private static final int REPEAT = 5;
 
     /**
-     * The name of the plan to transfer.
-     *
-     * In this case we will transfer the CTS.xml file.
+     * The device-side location to write the file to.
      */
-    private static final String PLAN_NAME = "CTS";
+    private static final String FILE_PATH = "/data/local/tmp/%s";
 
     /**
-     * A reference to the build.
+     * The name of the file to transfer.
+     *
+     * In this case we will transfer this test's module config.
      */
-    private CtsBuildHelper mBuild;
+    private static final String FILE_NAME = "CtsSampleHostTestCases.config";
+
+    /**
+     * A helper to access resources in the build.
+     */
+    private CompatibilityBuildHelper mBuildHelper;
 
     /**
      * A reference to the device under test.
@@ -81,7 +83,7 @@
     @Override
     public void setBuild(IBuildInfo buildInfo) {
         // Get the build, this is used to access the APK.
-        mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+        mBuildHelper = new CompatibilityBuildHelper(buildInfo);
     }
 
     @Override
@@ -100,13 +102,10 @@
      */
     public void testTransferTime() throws Exception {
         final ITestDevice device = mDevice;
-        // Get the external storage location and ensure its not null.
-        final String externalStorePath = mDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
-        assertNotNull("External storage location no found", externalStorePath);
         // Create the device side path where the file will be transfered.
-        final String devicePath = String.format("%s/%s", externalStorePath, "tmp_testPushPull.txt");
-        // Get the file from the build.
-        final File testFile = mBuild.getTestPlanFile(PLAN_NAME);
+        final String devicePath = String.format(FILE_PATH, "tmp_testPushPull.txt");
+        // Get this test's module config file from the build.
+        final File testFile = new File(mBuildHelper.getTestsDir(), FILE_NAME);
         double[] result = MeasureTime.measure(REPEAT, new MeasureRun() {
             @Override
             public void prepare(int i) throws Exception {
@@ -133,15 +132,15 @@
         // Compute the stats.
         Stat.StatResult stat = Stat.getStat(result);
         // Get the report for this test and add the results to record.
-        HostReportLog report = new HostReportLog(mDevice.getSerialNumber(), mAbi.getName(),
-                ReportLog.getClassMethodNames());
-        report.printArray("Times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
-        report.printValue("Min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
-        report.printValue("Max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
+        MetricsReportLog report = new MetricsReportLog(mDevice.getSerialNumber(), mAbi.getName(),
+                String.format("%s#testTransferTime", getClass().getCanonicalName()));
+        report.addValues("Times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.addValue("Min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.addValue("Max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
         // Every report must have a summary,
-        report.printSummary("Average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.setSummary("Average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
         // Send the report to Tradefed.
-        report.deliverReportToHost();
+        report.submit();
     }
 
     /**
diff --git a/hostsidetests/sample/src/android/sample/cts/SampleHostTest.java b/hostsidetests/sample/src/android/sample/cts/SampleHostTest.java
index ab7e0b0..df86444 100644
--- a/hostsidetests/sample/src/android/sample/cts/SampleHostTest.java
+++ b/hostsidetests/sample/src/android/sample/cts/SampleHostTest.java
@@ -16,27 +16,20 @@
 
 package android.sample.cts;
 
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
-import com.android.tradefed.build.IBuildInfo;
+import com.android.compatibility.common.util.DynamicConfigHostSide;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
 
-import java.io.File;
-import java.lang.String;
 import java.util.Scanner;
 
 /**
  * Test to check the APK logs to Logcat.
  *
  * When this test builds, it also builds {@link android.sample.app.SampleDeviceActivity} into an APK
- * which it then installs at runtime and starts. The activity simply prints a message to Logcat and
- * then gets uninstalled.
+ * which it then installed at runtime and started. The activity simply prints a message to Logcat
+ * and then gets uninstalled.
  */
-public class SampleHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+public class SampleHostTest extends DeviceTestCase {
 
     /**
      * The package name of the APK.
@@ -44,11 +37,6 @@
     private static final String PACKAGE = "android.sample.app";
 
     /**
-     * The file name of the APK.
-     */
-    private static final String APK = "CtsSampleDeviceApp.apk";
-
-    /**
      * The class name of the main activity in the APK.
      */
     private static final String CLASS = "SampleDeviceActivity";
@@ -65,51 +53,21 @@
     private static final String TEST_STRING = "SampleTestString";
 
     /**
-     * The ABI to use.
+     * Test if dynamic config on the host side works
+     * @throws Exception
      */
-    private IAbi mAbi;
+    public void testDynamicConfigLocal() throws Exception {
+        DynamicConfigHostSide config = new DynamicConfigHostSide("CtsSampleHostTestCases");
+        assertEquals("local-config-val", config.getConfig("local-config"));
+    }
 
     /**
-     * A reference to the build.
+     * Test if dynamic config override on the host side works
+     * @throws Exception
      */
-    private CtsBuildHelper mBuild;
-
-    /**
-     * A reference to the device under test.
-     */
-    private ITestDevice mDevice;
-
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        // Get the build, this is used to access the APK.
-        mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // Get the device, this gives a handle to run commands and install APKs.
-        mDevice = getDevice();
-        // Remove any previously installed versions of this APK.
-        mDevice.uninstallPackage(PACKAGE);
-        // Get the APK from the build.
-        File app = mBuild.getTestApp(APK);
-        // Get the ABI flag.
-        String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-        // Install the APK on the device.
-        mDevice.installPackage(app, false, options);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        // Remove the package once complete.
-        mDevice.uninstallPackage(PACKAGE);
-        super.tearDown();
+    public void testDynamicConfigOverride() throws Exception {
+        DynamicConfigHostSide config = new DynamicConfigHostSide("CtsSampleHostTestCases");
+        assertEquals("host-1.0-cts-keyone", config.getConfig("sample_host_key_one"));
     }
 
     /**
@@ -118,12 +76,13 @@
      * @throws Exception
      */
     public void testLogcat() throws Exception {
+        ITestDevice device = getDevice();
         // Clear logcat.
-        mDevice.executeAdbCommand("logcat", "-c");
+        device.executeAdbCommand("logcat", "-c");
         // Start the APK and wait for it to complete.
-        mDevice.executeShellCommand(START_COMMAND);
+        device.executeShellCommand(START_COMMAND);
         // Dump logcat.
-        String logs = mDevice.executeAdbCommand("logcat", "-v", "brief", "-d", CLASS + ":I", "*:S");
+        String logs = device.executeAdbCommand("logcat", "-v", "brief", "-d", CLASS + ":I", "*:S");
         // Search for string.
         String testString = "";
         Scanner in = new Scanner(logs);
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index ad708ca..5bac9a7 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -20,6 +20,9 @@
 
 LOCAL_MODULE_TAGS := optional
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsSecurityHostTestCases
 
diff --git a/hostsidetests/security/AndroidTest.xml b/hostsidetests/security/AndroidTest.xml
new file mode 100644
index 0000000..e521761
--- /dev/null
+++ b/hostsidetests/security/AndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for the CTS Security host tests">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsSecurityHostTestCases.jar" />
+        <option name="runtime-hint" value="12m13s" />
+    </test>
+</configuration>
diff --git a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
deleted file mode 100644
index 132596c..0000000
--- a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
+++ /dev/null
@@ -1,776 +0,0 @@
-/*
- * 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.cts.security;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.CollectingOutputReceiver;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.String;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.Scanner;
-import java.util.Set;
-
-/**
- * Host-side SELinux tests.
- *
- * These tests analyze the policy file in use on the subject device directly or
- * run as the shell user to evaluate aspects of the state of SELinux on the test
- * device which otherwise would not be available to a normal apk.
- */
-public class SELinuxHostTest extends DeviceTestCase {
-
-    private File sepolicyAnalyze;
-    private File checkSeapp;
-    private File checkFc;
-    private File aospSeappFile;
-    private File aospFcFile;
-    private File aospPcFile;
-    private File aospSvcFile;
-    private File devicePolicyFile;
-    private File deviceSeappFile;
-    private File deviceFcFile;
-    private File devicePcFile;
-    private File deviceSvcFile;
-    private File seappNeverAllowFile;
-
-    /**
-     * A reference to the device under test.
-     */
-    private ITestDevice mDevice;
-
-    private File copyResourceToTempFile(String resName) throws IOException {
-        InputStream is = this.getClass().getResourceAsStream(resName);
-        File tempFile = File.createTempFile("SELinuxHostTest", ".tmp");
-        FileOutputStream os = new FileOutputStream(tempFile);
-        int rByte = 0;
-        while ((rByte = is.read()) != -1) {
-            os.write(rByte);
-        }
-        os.flush();
-        os.close();
-        tempFile.deleteOnExit();
-        return tempFile;
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mDevice = getDevice();
-
-        /* retrieve the sepolicy-analyze executable from jar */
-        sepolicyAnalyze = copyResourceToTempFile("/sepolicy-analyze");
-        sepolicyAnalyze.setExecutable(true);
-
-        /* retrieve the checkseapp executable from jar */
-        checkSeapp = copyResourceToTempFile("/checkseapp");
-        checkSeapp.setExecutable(true);
-
-        /* retrieve the checkfc executable from jar */
-        checkFc = copyResourceToTempFile("/checkfc");
-        checkFc.setExecutable(true);
-
-        /* obtain sepolicy file from running device */
-        devicePolicyFile = File.createTempFile("sepolicy", ".tmp");
-        devicePolicyFile.deleteOnExit();
-        mDevice.pullFile("/sys/fs/selinux/policy", devicePolicyFile);
-
-        /* obtain seapp_contexts file from running device */
-        deviceSeappFile = File.createTempFile("seapp_contexts", ".tmp");
-        deviceSeappFile.deleteOnExit();
-        mDevice.pullFile("/seapp_contexts", deviceSeappFile);
-
-        /* obtain file_contexts.bin file from running device */
-        deviceFcFile = File.createTempFile("file_contexts", ".bin");
-        deviceFcFile.deleteOnExit();
-        mDevice.pullFile("/file_contexts.bin", deviceFcFile);
-
-        /* obtain property_contexts file from running device */
-        devicePcFile = File.createTempFile("property_contexts", ".tmp");
-        devicePcFile.deleteOnExit();
-        mDevice.pullFile("/property_contexts", devicePcFile);
-
-        /* obtain service_contexts file from running device */
-        deviceSvcFile = File.createTempFile("service_contexts", ".tmp");
-        deviceSvcFile.deleteOnExit();
-        mDevice.pullFile("/service_contexts", deviceSvcFile);
-
-        /* retrieve the AOSP *_contexts files from jar */
-        aospSeappFile = copyResourceToTempFile("/general_seapp_contexts");
-        aospFcFile = copyResourceToTempFile("/general_file_contexts.bin");
-        aospPcFile = copyResourceToTempFile("/general_property_contexts");
-        aospSvcFile = copyResourceToTempFile("/general_service_contexts");
-        seappNeverAllowFile = copyResourceToTempFile("/general_seapp_neverallows");
-    }
-
-    /**
-     * Tests that all domains in the running policy file are in enforcing mode
-     *
-     * @throws Exception
-     */
-    public void testAllEnforcing() throws Exception {
-
-        /* run sepolicy-analyze permissive check on policy file */
-        ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
-                devicePolicyFile.getAbsolutePath(), "permissive");
-        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
-        pb.redirectErrorStream(true);
-        Process p = pb.start();
-        p.waitFor();
-        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
-        String line;
-        StringBuilder errorString = new StringBuilder();
-        while ((line = result.readLine()) != null) {
-            errorString.append(line);
-            errorString.append("\n");
-        }
-        assertTrue("The following SELinux domains were found to be in permissive mode:\n"
-                   + errorString, errorString.length() == 0);
-    }
-
-    /**
-     * Asserts that specified type is not associated with the specified
-     * attribute.
-     *
-     * @param attribute
-     *  The attribute name.
-     * @param type
-     *  The type name.
-     */
-    private void assertNotInAttribute(String attribute, String badtype) throws Exception {
-        /* run sepolicy-analyze attribute check on policy file */
-        ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
-                devicePolicyFile.getAbsolutePath(), "attribute", attribute);
-        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
-        pb.redirectErrorStream(true);
-        Process p = pb.start();
-        p.waitFor();
-        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
-        String type;
-        while ((type = result.readLine()) != null) {
-            assertFalse("Attribute " + attribute + " includes " + type + "\n",
-                        type.equals(badtype));
-        }
-    }
-
-    /**
-     * Tests that mlstrustedsubject does not include untrusted_app
-     * and that mlstrustedobject does not include app_data_file.
-     * This helps prevent circumventing the per-user isolation of
-     * normal apps via levelFrom=user.
-     *
-     * @throws Exception
-     */
-    public void testMLSAttributes() throws Exception {
-        assertNotInAttribute("mlstrustedsubject", "untrusted_app");
-        assertNotInAttribute("mlstrustedobject", "app_data_file");
-    }
-
-    /**
-     * Tests that the seapp_contexts file on the device is valid.
-     *
-     * @throws Exception
-     */
-    public void testValidSeappContexts() throws Exception {
-
-        /* run checkseapp on seapp_contexts */
-        ProcessBuilder pb = new ProcessBuilder(checkSeapp.getAbsolutePath(),
-                "-p", devicePolicyFile.getAbsolutePath(),
-                seappNeverAllowFile.getAbsolutePath(),
-                deviceSeappFile.getAbsolutePath());
-        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
-        pb.redirectErrorStream(true);
-        Process p = pb.start();
-        p.waitFor();
-        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
-        String line;
-        StringBuilder errorString = new StringBuilder();
-        while ((line = result.readLine()) != null) {
-            errorString.append(line);
-            errorString.append("\n");
-        }
-        assertTrue("The seapp_contexts file was invalid:\n"
-                   + errorString, errorString.length() == 0);
-    }
-
-    /**
-     * Asserts that the actual file contents starts with the expected file
-     * contents.
-     *
-     * @param expectedFile
-     *  The file with the expected contents.
-     * @param actualFile
-     *  The actual file being checked.
-     */
-    private void assertFileStartsWith(File expectedFile, File actualFile) throws Exception {
-        BufferedReader expectedReader = new BufferedReader(new FileReader(expectedFile.getAbsolutePath()));
-        BufferedReader actualReader = new BufferedReader(new FileReader(actualFile.getAbsolutePath()));
-        String expectedLine, actualLine;
-        while ((expectedLine = expectedReader.readLine()) != null) {
-            actualLine = actualReader.readLine();
-            assertEquals("Lines do not match:", expectedLine, actualLine);
-        }
-    }
-
-    /**
-     * Tests that the seapp_contexts file on the device contains
-     * the standard AOSP entries.
-     *
-     * @throws Exception
-     */
-    public void testAospSeappContexts() throws Exception {
-        assertFileStartsWith(aospSeappFile, deviceSeappFile);
-    }
-
-    /**
-     * Tests that the file_contexts.bin file on the device contains
-     * the standard AOSP entries.
-     *
-     * @throws Exception
-     */
-    public void testAospFileContexts() throws Exception {
-        /* run checkfc -c general_file_contexts.bin file_contexts.bin */
-        ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
-                "-c", aospFcFile.getAbsolutePath(),
-                deviceFcFile.getAbsolutePath());
-        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
-        pb.redirectErrorStream(true);
-        Process p = pb.start();
-        p.waitFor();
-        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
-        String line = result.readLine();
-        assertTrue("The file_contexts.bin file did not include the AOSP entries:\n"
-                   + line + "\n",
-                   line.equals("equal") || line.equals("subset"));
-    }
-
-    /**
-     * Tests that the property_contexts file on the device contains
-     * the standard AOSP entries.
-     *
-     * @throws Exception
-     */
-    public void testAospPropertyContexts() throws Exception {
-        assertFileStartsWith(aospPcFile, devicePcFile);
-    }
-
-    /**
-     * Tests that the service_contexts file on the device contains
-     * the standard AOSP entries.
-     *
-     * @throws Exception
-     */
-    public void testAospServiceContexts() throws Exception {
-        assertFileStartsWith(aospSvcFile, deviceSvcFile);
-    }
-
-    /**
-     * Tests that the file_contexts.bin file on the device is valid.
-     *
-     * @throws Exception
-     */
-    public void testValidFileContexts() throws Exception {
-
-        /* run checkfc sepolicy file_contexts.bin */
-        ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
-                devicePolicyFile.getAbsolutePath(),
-                deviceFcFile.getAbsolutePath());
-        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
-        pb.redirectErrorStream(true);
-        Process p = pb.start();
-        p.waitFor();
-        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
-        String line;
-        StringBuilder errorString = new StringBuilder();
-        while ((line = result.readLine()) != null) {
-            errorString.append(line);
-            errorString.append("\n");
-        }
-        assertTrue("The file_contexts.bin file was invalid:\n"
-                   + errorString, errorString.length() == 0);
-    }
-
-    /**
-     * Tests that the property_contexts file on the device is valid.
-     *
-     * @throws Exception
-     */
-    public void testValidPropertyContexts() throws Exception {
-
-        /* run checkfc -p on property_contexts */
-        ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
-                "-p", devicePolicyFile.getAbsolutePath(),
-                devicePcFile.getAbsolutePath());
-        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
-        pb.redirectErrorStream(true);
-        Process p = pb.start();
-        p.waitFor();
-        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
-        String line;
-        StringBuilder errorString = new StringBuilder();
-        while ((line = result.readLine()) != null) {
-            errorString.append(line);
-            errorString.append("\n");
-        }
-        assertTrue("The property_contexts file was invalid:\n"
-                   + errorString, errorString.length() == 0);
-    }
-
-    /**
-     * Tests that the service_contexts file on the device is valid.
-     *
-     * @throws Exception
-     */
-    public void testValidServiceContexts() throws Exception {
-
-        /* run checkfc -s on service_contexts */
-        ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
-                "-s", devicePolicyFile.getAbsolutePath(),
-                deviceSvcFile.getAbsolutePath());
-        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
-        pb.redirectErrorStream(true);
-        Process p = pb.start();
-        p.waitFor();
-        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
-        String line;
-        StringBuilder errorString = new StringBuilder();
-        while ((line = result.readLine()) != null) {
-            errorString.append(line);
-            errorString.append("\n");
-        }
-        assertTrue("The service_contexts file was invalid:\n"
-                   + errorString, errorString.length() == 0);
-    }
-
-   /**
-     * Tests that the policy defines no booleans (runtime conditional policy).
-     *
-     * @throws Exception
-     */
-    public void testNoBooleans() throws Exception {
-
-        /* run sepolicy-analyze booleans check on policy file */
-        ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
-                devicePolicyFile.getAbsolutePath(), "booleans");
-        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
-        pb.redirectErrorStream(true);
-        Process p = pb.start();
-        p.waitFor();
-        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
-        String line;
-        StringBuilder errorString = new StringBuilder();
-        while ((line = result.readLine()) != null) {
-            errorString.append(line);
-            errorString.append("\n");
-        }
-        assertTrue("The policy contained booleans:\n"
-                   + errorString, errorString.length() == 0);
-    }
-
-    /**
-     * Tests that important domain labels are being appropriately applied.
-     */
-
-    /**
-     * Asserts that no processes are running in a domain.
-     *
-     * @param domain
-     *  The domain or SELinux context to check.
-     */
-    private void assertDomainEmpty(String domain) throws DeviceNotAvailableException {
-        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
-        String msg = "Expected no processes in SELinux domain \"" + domain + "\""
-            + " Found: \"" + procs + "\"";
-        assertNull(msg, procs);
-    }
-
-    /**
-     * Asserts that a domain exists and that only one, well defined, process is
-     * running in that domain.
-     *
-     * @param domain
-     *  The domain or SELinux context to check.
-     * @param executable
-     *  The path of the executable or application package name.
-     */
-    private void assertDomainOne(String domain, String executable) throws DeviceNotAvailableException {
-        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
-        List<ProcessDetails> exeProcs = ProcessDetails.getExeMap(mDevice).get(executable);
-        String msg = "Expected 1 process in SELinux domain \"" + domain + "\""
-            + " Found \"" + procs + "\"";
-        assertNotNull(msg, procs);
-        assertEquals(msg, 1, procs.size());
-
-        msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
-            + "Found: \"" + procs + "\"";
-        assertEquals(msg, executable, procs.get(0).procTitle);
-
-        msg = "Expected 1 process with executable \"" + executable + "\""
-            + " Found \"" + procs + "\"";
-        assertNotNull(msg, exeProcs);
-        assertEquals(msg, 1, exeProcs.size());
-
-        msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
-            + "Found: \"" + procs + "\"";
-        assertEquals(msg, domain, exeProcs.get(0).label);
-    }
-
-    /**
-     * Asserts that a domain may exist. If a domain exists, the cardinality of
-     * the domain is verified to be 1 and that the correct process is running in
-     * that domain.
-     *
-     * @param domain
-     *  The domain or SELinux context to check.
-     * @param executable
-     *  The path of the executable or application package name.
-     */
-    private void assertDomainZeroOrOne(String domain, String executable)
-        throws DeviceNotAvailableException {
-        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
-        List<ProcessDetails> exeProcs = ProcessDetails.getExeMap(mDevice).get(executable);
-
-        if (procs != null) {
-            String msg = "Expected 1 process in SELinux domain \"" + domain + "\""
-            + " Found: \"" + procs + "\"";
-            assertEquals(msg, 1, procs.size());
-
-            msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
-                + "Found: \"" + procs.get(0) + "\"";
-            assertEquals(msg, executable, procs.get(0).procTitle);
-        }
-
-        if (exeProcs != null) {
-            String msg = "Expected 1 process with executable \"" + executable + "\""
-            + " Found: \"" + procs + "\"";
-            assertEquals(msg, 1, exeProcs.size());
-
-            msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
-                + "Found: \"" + procs.get(0) + "\"";
-            assertEquals(msg, domain, exeProcs.get(0).label);
-        }
-    }
-
-    /**
-     * Asserts that a domain must exist, and that the cardinality is greater
-     * than or equal to 1.
-     *
-     * @param domain
-     *  The domain or SELinux context to check.
-     * @param executables
-     *  The path of the allowed executables or application package names.
-     */
-    private void assertDomainN(String domain, String... executables)
-        throws DeviceNotAvailableException {
-        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
-        String msg = "Expected 1 or more processes in SELinux domain but found none.";
-        assertNotNull(msg, procs);
-
-        Set<String> execList = new HashSet<String>(Arrays.asList(executables));
-
-        for (ProcessDetails p : procs) {
-            msg = "Expected one of \"" + execList + "\" in SELinux domain \"" + domain + "\""
-                + " Found: \"" + p + "\"";
-            assertTrue(msg, execList.contains(p.procTitle));
-        }
-
-        for (String exe : executables) {
-            List<ProcessDetails> exeProcs = ProcessDetails.getExeMap(mDevice).get(exe);
-
-            if (exeProcs != null) {
-                for (ProcessDetails p : exeProcs) {
-                    msg = "Expected executable \"" + exe + "\" in SELinux domain \""
-                        + domain + "\"" + " Found: \"" + p + "\"";
-                    assertEquals(msg, domain, p.label);
-                }
-            }
-        }
-    }
-
-    /**
-     * Asserts that a domain, if it exists, is only running the listed executables.
-     *
-     * @param domain
-     *  The domain or SELinux context to check.
-     * @param executables
-     *  The path of the allowed executables or application package names.
-     */
-    private void assertDomainHasExecutable(String domain, String... executables)
-        throws DeviceNotAvailableException {
-        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
-
-        if (procs != null) {
-            Set<String> execList = new HashSet<String>(Arrays.asList(executables));
-
-            for (ProcessDetails p : procs) {
-                String msg = "Expected one of \"" + execList + "\" in SELinux domain \""
-                    + domain + "\"" + " Found: \"" + p + "\"";
-                assertTrue(msg, execList.contains(p.procTitle));
-            }
-        }
-
-        for (String exe : executables) {
-            List<ProcessDetails> exeProcs = ProcessDetails.getExeMap(mDevice).get(exe);
-
-            if (exeProcs != null) {
-                for (ProcessDetails p : exeProcs) {
-                    String msg = "Expected executable \"" + exe + "\" in SELinux domain \""
-                        + domain + "\"" + " Found: \"" + p + "\"";
-                    assertEquals(msg, domain, p.label);
-                }
-            }
-        }
-    }
-
-    /* Init is always there */
-    public void testInitDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:init:s0", "/init");
-    }
-
-    /* Ueventd is always there */
-    public void testUeventdDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:ueventd:s0", "/sbin/ueventd");
-    }
-
-    /* Devices always have healthd */
-    public void testHealthdDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:healthd:s0", "/sbin/healthd");
-    }
-
-    /* Servicemanager is always there */
-    public void testServicemanagerDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:servicemanager:s0", "/system/bin/servicemanager");
-    }
-
-    /* Vold is always there */
-    public void testVoldDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:vold:s0", "/system/bin/vold");
-    }
-
-    /* netd is always there */
-    public void testNetdDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:netd:s0", "/system/bin/netd");
-    }
-
-    /* Debuggerd is always there */
-    public void testDebuggerdDomain() throws DeviceNotAvailableException {
-        assertDomainN("u:r:debuggerd:s0", "/system/bin/debuggerd", "/system/bin/debuggerd64");
-    }
-
-    /* Surface flinger is always there */
-    public void testSurfaceflingerDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:surfaceflinger:s0", "/system/bin/surfaceflinger");
-    }
-
-    /* Zygote is always running */
-    public void testZygoteDomain() throws DeviceNotAvailableException {
-        assertDomainN("u:r:zygote:s0", "zygote", "zygote64");
-    }
-
-    /* Checks drmserver for devices that require it */
-    public void testDrmServerDomain() throws DeviceNotAvailableException {
-        assertDomainZeroOrOne("u:r:drmserver:s0", "/system/bin/drmserver");
-    }
-
-    /* Media server is always running */
-    public void testMediaserverDomain() throws DeviceNotAvailableException {
-        assertDomainN("u:r:mediaserver:s0", "media.log", "/system/bin/mediaserver");
-    }
-
-    /* Installd is always running */
-    public void testInstalldDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:installd:s0", "/system/bin/installd");
-    }
-
-    /* keystore is always running */
-    public void testKeystoreDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:keystore:s0", "/system/bin/keystore");
-    }
-
-    /* System server better be running :-P */
-    public void testSystemServerDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:system_server:s0", "system_server");
-    }
-
-    /*
-     * Some OEMs do not use sdcardd so transient. Other OEMs have multiple sdcards
-     * so they run the daemon multiple times.
-     */
-    public void testSdcarddDomain() throws DeviceNotAvailableException {
-        assertDomainHasExecutable("u:r:sdcardd:s0", "/system/bin/sdcard");
-    }
-
-    /* Watchdogd may or may not be there */
-    public void testWatchdogdDomain() throws DeviceNotAvailableException {
-        assertDomainZeroOrOne("u:r:watchdogd:s0", "/sbin/watchdogd");
-    }
-
-    /* logd may or may not be there */
-    public void testLogdDomain() throws DeviceNotAvailableException {
-        assertDomainZeroOrOne("u:r:logd:s0", "/system/bin/logd");
-    }
-
-    /* lmkd may or may not be there */
-    public void testLmkdDomain() throws DeviceNotAvailableException {
-        assertDomainZeroOrOne("u:r:lmkd:s0", "/system/bin/lmkd");
-    }
-
-    /* Wifi may be off so cardinality of 0 or 1 is ok */
-    public void testWpaDomain() throws DeviceNotAvailableException {
-        assertDomainZeroOrOne("u:r:wpa:s0", "/system/bin/wpa_supplicant");
-    }
-
-    /*
-     * Nothing should be running in this domain, cardinality test is all thats
-     * needed
-     */
-    public void testInitShellDomain() throws DeviceNotAvailableException {
-        assertDomainEmpty("u:r:init_shell:s0");
-    }
-
-    /*
-     * Nothing should be running in this domain, cardinality test is all thats
-     * needed
-     */
-    public void testRecoveryDomain() throws DeviceNotAvailableException {
-        assertDomainEmpty("u:r:recovery:s0");
-    }
-
-    /*
-     * Nothing should be running in this domain, cardinality test is all thats
-     * needed
-     */
-    public void testSuDomain() throws DeviceNotAvailableException {
-        assertDomainEmpty("u:r:su:s0");
-    }
-
-    /*
-     * All kthreads should be in kernel context.
-     */
-    public void testKernelDomain() throws DeviceNotAvailableException {
-        String domain = "u:r:kernel:s0";
-        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
-        if (procs != null) {
-            for (ProcessDetails p : procs) {
-                assertTrue("Non Kernel thread \"" + p + "\" found!", p.isKernel());
-            }
-        }
-    }
-
-    private static class ProcessDetails {
-        public String label;
-        public String user;
-        public int pid;
-        public int ppid;
-        public String procTitle;
-
-        private static HashMap<String, ArrayList<ProcessDetails>> procMap;
-        private static HashMap<String, ArrayList<ProcessDetails>> exeMap;
-        private static int kernelParentThreadpid = -1;
-
-        ProcessDetails(String label, String user, int pid, int ppid, String procTitle) {
-            this.label = label;
-            this.user = user;
-            this.pid = pid;
-            this.ppid = ppid;
-            this.procTitle = procTitle;
-        }
-
-        @Override
-        public String toString() {
-            return "label: " + label
-                    + " user: " + user
-                    + " pid: " + pid
-                    + " ppid: " + ppid
-                    + " cmd: " + procTitle;
-        }
-
-
-        private static void createProcMap(ITestDevice tDevice) throws DeviceNotAvailableException {
-
-            /* take the output of a ps -Z to do our analysis */
-            CollectingOutputReceiver psOut = new CollectingOutputReceiver();
-            tDevice.executeShellCommand("ps -Z", psOut);
-            String psOutString = psOut.getOutput();
-            Pattern p = Pattern.compile(
-                    "^([\\w_:]+)\\s+([\\w_]+)\\s+(\\d+)\\s+(\\d+)\\s+(\\p{Graph}+)$",
-                    Pattern.MULTILINE);
-            Matcher m = p.matcher(psOutString);
-            procMap = new HashMap<String, ArrayList<ProcessDetails>>();
-            exeMap = new HashMap<String, ArrayList<ProcessDetails>>();
-            while(m.find()) {
-                String domainLabel = m.group(1);
-                String user = m.group(2);
-                int pid = Integer.parseInt(m.group(3));
-                int ppid = Integer.parseInt(m.group(4));
-                String procTitle = m.group(5);
-                ProcessDetails proc = new ProcessDetails(domainLabel, user, pid, ppid, procTitle);
-                if (procMap.get(domainLabel) == null) {
-                    procMap.put(domainLabel, new ArrayList<ProcessDetails>());
-                }
-                procMap.get(domainLabel).add(proc);
-                if (procTitle.equals("kthreadd") && ppid == 0) {
-                    kernelParentThreadpid = pid;
-                }
-                if (exeMap.get(procTitle) == null) {
-                    exeMap.put(procTitle, new ArrayList<ProcessDetails>());
-                }
-                exeMap.get(procTitle).add(proc);
-            }
-        }
-
-        public static HashMap<String, ArrayList<ProcessDetails>> getProcMap(ITestDevice tDevice)
-                throws DeviceNotAvailableException{
-            if (procMap == null) {
-                createProcMap(tDevice);
-            }
-            return procMap;
-        }
-
-        public static HashMap<String, ArrayList<ProcessDetails>> getExeMap(ITestDevice tDevice)
-                throws DeviceNotAvailableException{
-            if (exeMap == null) {
-                createProcMap(tDevice);
-            }
-            return exeMap;
-        }
-
-        public boolean isKernel() {
-            return (pid == kernelParentThreadpid || ppid == kernelParentThreadpid);
-        }
-    }
-}
diff --git a/hostsidetests/security/src/android/security/cts/EncryptionHostTest.java b/hostsidetests/security/src/android/security/cts/EncryptionHostTest.java
new file mode 100644
index 0000000..5e12143
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/EncryptionHostTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import java.util.UUID;
+
+/**
+ * Host side encryption tests
+ *
+ * These tests analyze a userdebug device for correct encryption properties
+ */
+public class EncryptionHostTest extends DeviceTestCase {
+    ITestDevice mDevice;
+    boolean mUserDebug;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDevice = getDevice();
+        mUserDebug = "userdebug".equals(mDevice.executeShellCommand("getprop ro.build.type").trim());
+        if (!mUserDebug) {
+            return;
+        }
+
+        mDevice.executeAdbCommand("root");
+        assertTrue(mDevice.isAdbRoot());
+    }
+
+    public void testEncrypted() throws DeviceNotAvailableException {
+        if (!mUserDebug || !mDevice.isDeviceEncrypted()) {
+            return;
+        }
+        /*
+        // Create file with name and contents a random UUID so we can search for it
+        String uuid = UUID.randomUUID().toString();
+        mDevice.executeShellCommand("echo " + uuid + " > /data/local/tmp/" + uuid);
+        String uuidReturned = mDevice.executeShellCommand("cat /data/local/tmp/" + uuid).trim();
+        assertTrue(uuid.equals(uuidReturned));
+
+        // Get name of /data device
+        String fstabName = mDevice.executeShellCommand("ls /fstab.*");
+        String[] fstab = mDevice.executeShellCommand("cat " + fstabName).split("\n");
+        String path = null;
+        for (String line : fstab) {
+            String[] entries = line.split("[ \t]+");
+            if (entries.length < 2) continue;
+            if ("/data".equals(entries[1])) {
+                path = entries[0];
+                break;
+            }
+        }
+        assertFalse(path == null);
+
+        // grep it for the data
+        String result = mDevice.executeShellCommand("grep " + uuid + " " + path + " ").trim();
+        assertTrue("".equals(result));
+
+        // Clean up
+        mDevice.executeShellCommand("rm /data/local/tmp/" + uuid);
+        */
+    }
+}
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
new file mode 100644
index 0000000..022e2f4
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -0,0 +1,773 @@
+/*
+ * 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.security.cts;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.String;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.Scanner;
+import java.util.Set;
+
+/**
+ * Host-side SELinux tests.
+ *
+ * These tests analyze the policy file in use on the subject device directly or
+ * run as the shell user to evaluate aspects of the state of SELinux on the test
+ * device which otherwise would not be available to a normal apk.
+ */
+public class SELinuxHostTest extends DeviceTestCase {
+
+    private File sepolicyAnalyze;
+    private File checkSeapp;
+    private File checkFc;
+    private File aospSeappFile;
+    private File aospFcFile;
+    private File aospPcFile;
+    private File aospSvcFile;
+    private File devicePolicyFile;
+    private File deviceSeappFile;
+    private File deviceFcFile;
+    private File devicePcFile;
+    private File deviceSvcFile;
+    private File seappNeverAllowFile;
+
+    /**
+     * A reference to the device under test.
+     */
+    private ITestDevice mDevice;
+
+    private File copyResourceToTempFile(String resName) throws IOException {
+        InputStream is = this.getClass().getResourceAsStream(resName);
+        File tempFile = File.createTempFile("SELinuxHostTest", ".tmp");
+        FileOutputStream os = new FileOutputStream(tempFile);
+        int rByte = 0;
+        while ((rByte = is.read()) != -1) {
+            os.write(rByte);
+        }
+        os.flush();
+        os.close();
+        tempFile.deleteOnExit();
+        return tempFile;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDevice = getDevice();
+
+        /* retrieve the sepolicy-analyze executable from jar */
+        sepolicyAnalyze = copyResourceToTempFile("/sepolicy-analyze");
+        sepolicyAnalyze.setExecutable(true);
+
+        /* retrieve the checkseapp executable from jar */
+        checkSeapp = copyResourceToTempFile("/checkseapp");
+        checkSeapp.setExecutable(true);
+
+        /* retrieve the checkfc executable from jar */
+        checkFc = copyResourceToTempFile("/checkfc");
+        checkFc.setExecutable(true);
+
+        /* obtain sepolicy file from running device */
+        devicePolicyFile = File.createTempFile("sepolicy", ".tmp");
+        devicePolicyFile.deleteOnExit();
+        mDevice.pullFile("/sys/fs/selinux/policy", devicePolicyFile);
+
+        /* obtain seapp_contexts file from running device */
+        deviceSeappFile = File.createTempFile("seapp_contexts", ".tmp");
+        deviceSeappFile.deleteOnExit();
+        mDevice.pullFile("/seapp_contexts", deviceSeappFile);
+
+        /* obtain file_contexts.bin file from running device */
+        deviceFcFile = File.createTempFile("file_contexts", ".bin");
+        deviceFcFile.deleteOnExit();
+        mDevice.pullFile("/file_contexts.bin", deviceFcFile);
+
+        /* obtain property_contexts file from running device */
+        devicePcFile = File.createTempFile("property_contexts", ".tmp");
+        devicePcFile.deleteOnExit();
+        mDevice.pullFile("/property_contexts", devicePcFile);
+
+        /* obtain service_contexts file from running device */
+        deviceSvcFile = File.createTempFile("service_contexts", ".tmp");
+        deviceSvcFile.deleteOnExit();
+        mDevice.pullFile("/service_contexts", deviceSvcFile);
+
+        /* retrieve the AOSP *_contexts files from jar */
+        aospSeappFile = copyResourceToTempFile("/general_seapp_contexts");
+        aospFcFile = copyResourceToTempFile("/general_file_contexts.bin");
+        aospPcFile = copyResourceToTempFile("/general_property_contexts");
+        aospSvcFile = copyResourceToTempFile("/general_service_contexts");
+        seappNeverAllowFile = copyResourceToTempFile("/general_seapp_neverallows");
+    }
+
+    /**
+     * Tests that all domains in the running policy file are in enforcing mode
+     *
+     * @throws Exception
+     */
+    public void testAllEnforcing() throws Exception {
+
+        /* run sepolicy-analyze permissive check on policy file */
+        ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
+                devicePolicyFile.getAbsolutePath(), "permissive");
+        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+        pb.redirectErrorStream(true);
+        Process p = pb.start();
+        p.waitFor();
+        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String line;
+        StringBuilder errorString = new StringBuilder();
+        while ((line = result.readLine()) != null) {
+            errorString.append(line);
+            errorString.append("\n");
+        }
+        assertTrue("The following SELinux domains were found to be in permissive mode:\n"
+                   + errorString, errorString.length() == 0);
+    }
+
+    /**
+     * Asserts that specified type is not associated with the specified
+     * attribute.
+     *
+     * @param attribute
+     *  The attribute name.
+     * @param type
+     *  The type name.
+     */
+    private void assertNotInAttribute(String attribute, String badtype) throws Exception {
+        /* run sepolicy-analyze attribute check on policy file */
+        ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
+                devicePolicyFile.getAbsolutePath(), "attribute", attribute);
+        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+        pb.redirectErrorStream(true);
+        Process p = pb.start();
+        p.waitFor();
+        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String type;
+        while ((type = result.readLine()) != null) {
+            assertFalse("Attribute " + attribute + " includes " + type + "\n",
+                        type.equals(badtype));
+        }
+    }
+
+    /**
+     * Tests that mlstrustedsubject does not include untrusted_app
+     * and that mlstrustedobject does not include app_data_file.
+     * This helps prevent circumventing the per-user isolation of
+     * normal apps via levelFrom=user.
+     *
+     * @throws Exception
+     */
+    public void testMLSAttributes() throws Exception {
+        assertNotInAttribute("mlstrustedsubject", "untrusted_app");
+        assertNotInAttribute("mlstrustedobject", "app_data_file");
+    }
+
+    /**
+     * Tests that the seapp_contexts file on the device is valid.
+     *
+     * @throws Exception
+     */
+    public void testValidSeappContexts() throws Exception {
+
+        /* run checkseapp on seapp_contexts */
+        ProcessBuilder pb = new ProcessBuilder(checkSeapp.getAbsolutePath(),
+                "-p", devicePolicyFile.getAbsolutePath(),
+                seappNeverAllowFile.getAbsolutePath(),
+                deviceSeappFile.getAbsolutePath());
+        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+        pb.redirectErrorStream(true);
+        Process p = pb.start();
+        p.waitFor();
+        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String line;
+        StringBuilder errorString = new StringBuilder();
+        while ((line = result.readLine()) != null) {
+            errorString.append(line);
+            errorString.append("\n");
+        }
+        assertTrue("The seapp_contexts file was invalid:\n"
+                   + errorString, errorString.length() == 0);
+    }
+
+    /**
+     * Asserts that the actual file contents starts with the expected file
+     * contents.
+     *
+     * @param expectedFile
+     *  The file with the expected contents.
+     * @param actualFile
+     *  The actual file being checked.
+     */
+    private void assertFileStartsWith(File expectedFile, File actualFile) throws Exception {
+        BufferedReader expectedReader = new BufferedReader(new FileReader(expectedFile.getAbsolutePath()));
+        BufferedReader actualReader = new BufferedReader(new FileReader(actualFile.getAbsolutePath()));
+        String expectedLine, actualLine;
+        while ((expectedLine = expectedReader.readLine()) != null) {
+            actualLine = actualReader.readLine();
+            assertEquals("Lines do not match:", expectedLine, actualLine);
+        }
+    }
+
+    /**
+     * Tests that the seapp_contexts file on the device contains
+     * the standard AOSP entries.
+     *
+     * @throws Exception
+     */
+    public void testAospSeappContexts() throws Exception {
+        assertFileStartsWith(aospSeappFile, deviceSeappFile);
+    }
+
+    /**
+     * Tests that the file_contexts.bin file on the device contains
+     * the standard AOSP entries.
+     *
+     * @throws Exception
+     */
+    public void testAospFileContexts() throws Exception {
+        /* run checkfc -c general_file_contexts.bin file_contexts.bin */
+        ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
+                "-c", aospFcFile.getAbsolutePath(),
+                deviceFcFile.getAbsolutePath());
+        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+        pb.redirectErrorStream(true);
+        Process p = pb.start();
+        p.waitFor();
+        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String line = result.readLine();
+        assertTrue("The file_contexts.bin file did not include the AOSP entries:\n"
+                   + line + "\n",
+                   line.equals("equal") || line.equals("subset"));
+    }
+
+    /**
+     * Tests that the property_contexts file on the device contains
+     * the standard AOSP entries.
+     *
+     * @throws Exception
+     */
+    public void testAospPropertyContexts() throws Exception {
+        assertFileStartsWith(aospPcFile, devicePcFile);
+    }
+
+    /**
+     * Tests that the service_contexts file on the device contains
+     * the standard AOSP entries.
+     *
+     * @throws Exception
+     */
+    public void testAospServiceContexts() throws Exception {
+        assertFileStartsWith(aospSvcFile, deviceSvcFile);
+    }
+
+    /**
+     * Tests that the file_contexts.bin file on the device is valid.
+     *
+     * @throws Exception
+     */
+    public void testValidFileContexts() throws Exception {
+
+        /* run checkfc sepolicy file_contexts.bin */
+        ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
+                devicePolicyFile.getAbsolutePath(),
+                deviceFcFile.getAbsolutePath());
+        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+        pb.redirectErrorStream(true);
+        Process p = pb.start();
+        p.waitFor();
+        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String line;
+        StringBuilder errorString = new StringBuilder();
+        while ((line = result.readLine()) != null) {
+            errorString.append(line);
+            errorString.append("\n");
+        }
+        assertTrue("The file_contexts.bin file was invalid:\n"
+                   + errorString, errorString.length() == 0);
+    }
+
+    /**
+     * Tests that the property_contexts file on the device is valid.
+     *
+     * @throws Exception
+     */
+    public void testValidPropertyContexts() throws Exception {
+
+        /* run checkfc -p on property_contexts */
+        ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
+                "-p", devicePolicyFile.getAbsolutePath(),
+                devicePcFile.getAbsolutePath());
+        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+        pb.redirectErrorStream(true);
+        Process p = pb.start();
+        p.waitFor();
+        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String line;
+        StringBuilder errorString = new StringBuilder();
+        while ((line = result.readLine()) != null) {
+            errorString.append(line);
+            errorString.append("\n");
+        }
+        assertTrue("The property_contexts file was invalid:\n"
+                   + errorString, errorString.length() == 0);
+    }
+
+    /**
+     * Tests that the service_contexts file on the device is valid.
+     *
+     * @throws Exception
+     */
+    public void testValidServiceContexts() throws Exception {
+
+        /* run checkfc -s on service_contexts */
+        ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
+                "-s", devicePolicyFile.getAbsolutePath(),
+                deviceSvcFile.getAbsolutePath());
+        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+        pb.redirectErrorStream(true);
+        Process p = pb.start();
+        p.waitFor();
+        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String line;
+        StringBuilder errorString = new StringBuilder();
+        while ((line = result.readLine()) != null) {
+            errorString.append(line);
+            errorString.append("\n");
+        }
+        assertTrue("The service_contexts file was invalid:\n"
+                   + errorString, errorString.length() == 0);
+    }
+
+   /**
+     * Tests that the policy defines no booleans (runtime conditional policy).
+     *
+     * @throws Exception
+     */
+    public void testNoBooleans() throws Exception {
+
+        /* run sepolicy-analyze booleans check on policy file */
+        ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
+                devicePolicyFile.getAbsolutePath(), "booleans");
+        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+        pb.redirectErrorStream(true);
+        Process p = pb.start();
+        p.waitFor();
+        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String line;
+        StringBuilder errorString = new StringBuilder();
+        while ((line = result.readLine()) != null) {
+            errorString.append(line);
+            errorString.append("\n");
+        }
+        assertTrue("The policy contained booleans:\n"
+                   + errorString, errorString.length() == 0);
+    }
+
+    /**
+     * Tests that important domain labels are being appropriately applied.
+     */
+
+    /**
+     * Asserts that no processes are running in a domain.
+     *
+     * @param domain
+     *  The domain or SELinux context to check.
+     */
+    private void assertDomainEmpty(String domain) throws DeviceNotAvailableException {
+        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
+        String msg = "Expected no processes in SELinux domain \"" + domain + "\""
+            + " Found: \"" + procs + "\"";
+        assertNull(msg, procs);
+    }
+
+    /**
+     * Asserts that a domain exists and that only one, well defined, process is
+     * running in that domain.
+     *
+     * @param domain
+     *  The domain or SELinux context to check.
+     * @param executable
+     *  The path of the executable or application package name.
+     */
+    private void assertDomainOne(String domain, String executable) throws DeviceNotAvailableException {
+        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
+        List<ProcessDetails> exeProcs = ProcessDetails.getExeMap(mDevice).get(executable);
+        String msg = "Expected 1 process in SELinux domain \"" + domain + "\""
+            + " Found \"" + procs + "\"";
+        assertNotNull(msg, procs);
+        assertEquals(msg, 1, procs.size());
+
+        msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
+            + "Found: \"" + procs + "\"";
+        assertEquals(msg, executable, procs.get(0).procTitle);
+
+        msg = "Expected 1 process with executable \"" + executable + "\""
+            + " Found \"" + procs + "\"";
+        assertNotNull(msg, exeProcs);
+        assertEquals(msg, 1, exeProcs.size());
+
+        msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
+            + "Found: \"" + procs + "\"";
+        assertEquals(msg, domain, exeProcs.get(0).label);
+    }
+
+    /**
+     * Asserts that a domain may exist. If a domain exists, the cardinality of
+     * the domain is verified to be 1 and that the correct process is running in
+     * that domain.
+     *
+     * @param domain
+     *  The domain or SELinux context to check.
+     * @param executable
+     *  The path of the executable or application package name.
+     */
+    private void assertDomainZeroOrOne(String domain, String executable)
+        throws DeviceNotAvailableException {
+        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
+        List<ProcessDetails> exeProcs = ProcessDetails.getExeMap(mDevice).get(executable);
+
+        if (procs != null) {
+            String msg = "Expected 1 process in SELinux domain \"" + domain + "\""
+            + " Found: \"" + procs + "\"";
+            assertEquals(msg, 1, procs.size());
+
+            msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
+                + "Found: \"" + procs.get(0) + "\"";
+            assertEquals(msg, executable, procs.get(0).procTitle);
+        }
+
+        if (exeProcs != null) {
+            String msg = "Expected 1 process with executable \"" + executable + "\""
+            + " Found: \"" + procs + "\"";
+            assertEquals(msg, 1, exeProcs.size());
+
+            msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
+                + "Found: \"" + procs.get(0) + "\"";
+            assertEquals(msg, domain, exeProcs.get(0).label);
+        }
+    }
+
+    /**
+     * Asserts that a domain must exist, and that the cardinality is greater
+     * than or equal to 1.
+     *
+     * @param domain
+     *  The domain or SELinux context to check.
+     * @param executables
+     *  The path of the allowed executables or application package names.
+     */
+    private void assertDomainN(String domain, String... executables)
+        throws DeviceNotAvailableException {
+        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
+        String msg = "Expected 1 or more processes in SELinux domain but found none.";
+        assertNotNull(msg, procs);
+
+        Set<String> execList = new HashSet<String>(Arrays.asList(executables));
+
+        for (ProcessDetails p : procs) {
+            msg = "Expected one of \"" + execList + "\" in SELinux domain \"" + domain + "\""
+                + " Found: \"" + p + "\"";
+            assertTrue(msg, execList.contains(p.procTitle));
+        }
+
+        for (String exe : executables) {
+            List<ProcessDetails> exeProcs = ProcessDetails.getExeMap(mDevice).get(exe);
+
+            if (exeProcs != null) {
+                for (ProcessDetails p : exeProcs) {
+                    msg = "Expected executable \"" + exe + "\" in SELinux domain \""
+                        + domain + "\"" + " Found: \"" + p + "\"";
+                    assertEquals(msg, domain, p.label);
+                }
+            }
+        }
+    }
+
+    /**
+     * Asserts that a domain, if it exists, is only running the listed executables.
+     *
+     * @param domain
+     *  The domain or SELinux context to check.
+     * @param executables
+     *  The path of the allowed executables or application package names.
+     */
+    private void assertDomainHasExecutable(String domain, String... executables)
+        throws DeviceNotAvailableException {
+        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
+
+        if (procs != null) {
+            Set<String> execList = new HashSet<String>(Arrays.asList(executables));
+
+            for (ProcessDetails p : procs) {
+                String msg = "Expected one of \"" + execList + "\" in SELinux domain \""
+                    + domain + "\"" + " Found: \"" + p + "\"";
+                assertTrue(msg, execList.contains(p.procTitle));
+            }
+        }
+
+        for (String exe : executables) {
+            List<ProcessDetails> exeProcs = ProcessDetails.getExeMap(mDevice).get(exe);
+
+            if (exeProcs != null) {
+                for (ProcessDetails p : exeProcs) {
+                    String msg = "Expected executable \"" + exe + "\" in SELinux domain \""
+                        + domain + "\"" + " Found: \"" + p + "\"";
+                    assertEquals(msg, domain, p.label);
+                }
+            }
+        }
+    }
+
+    /* Init is always there */
+    public void testInitDomain() throws DeviceNotAvailableException {
+        assertDomainOne("u:r:init:s0", "/init");
+    }
+
+    /* Ueventd is always there */
+    public void testUeventdDomain() throws DeviceNotAvailableException {
+        assertDomainOne("u:r:ueventd:s0", "/sbin/ueventd");
+    }
+
+    /* Devices always have healthd */
+    public void testHealthdDomain() throws DeviceNotAvailableException {
+        assertDomainOne("u:r:healthd:s0", "/sbin/healthd");
+    }
+
+    /* Servicemanager is always there */
+    public void testServicemanagerDomain() throws DeviceNotAvailableException {
+        assertDomainOne("u:r:servicemanager:s0", "/system/bin/servicemanager");
+    }
+
+    /* Vold is always there */
+    public void testVoldDomain() throws DeviceNotAvailableException {
+        assertDomainOne("u:r:vold:s0", "/system/bin/vold");
+    }
+
+    /* netd is always there */
+    public void testNetdDomain() throws DeviceNotAvailableException {
+        assertDomainOne("u:r:netd:s0", "/system/bin/netd");
+    }
+
+    /* Debuggerd is always there */
+    public void testDebuggerdDomain() throws DeviceNotAvailableException {
+        assertDomainN("u:r:debuggerd:s0", "/system/bin/debuggerd", "/system/bin/debuggerd64");
+    }
+
+    /* Surface flinger is always there */
+    public void testSurfaceflingerDomain() throws DeviceNotAvailableException {
+        assertDomainOne("u:r:surfaceflinger:s0", "/system/bin/surfaceflinger");
+    }
+
+    /* Zygote is always running */
+    public void testZygoteDomain() throws DeviceNotAvailableException {
+        assertDomainN("u:r:zygote:s0", "zygote", "zygote64");
+    }
+
+    /* Checks drmserver for devices that require it */
+    public void testDrmServerDomain() throws DeviceNotAvailableException {
+        assertDomainZeroOrOne("u:r:drmserver:s0", "/system/bin/drmserver");
+    }
+
+    /* Media server is always running */
+    public void testMediaserverDomain() throws DeviceNotAvailableException {
+        assertDomainN("u:r:mediaserver:s0", "media.log", "/system/bin/mediaserver");
+    }
+
+    /* Installd is always running */
+    public void testInstalldDomain() throws DeviceNotAvailableException {
+        assertDomainOne("u:r:installd:s0", "/system/bin/installd");
+    }
+
+    /* keystore is always running */
+    public void testKeystoreDomain() throws DeviceNotAvailableException {
+        assertDomainOne("u:r:keystore:s0", "/system/bin/keystore");
+    }
+
+    /* System server better be running :-P */
+    public void testSystemServerDomain() throws DeviceNotAvailableException {
+        assertDomainOne("u:r:system_server:s0", "system_server");
+    }
+
+    /*
+     * Some OEMs do not use sdcardd so transient. Other OEMs have multiple sdcards
+     * so they run the daemon multiple times.
+     */
+    public void testSdcarddDomain() throws DeviceNotAvailableException {
+        assertDomainHasExecutable("u:r:sdcardd:s0", "/system/bin/sdcard");
+    }
+
+    /* Watchdogd may or may not be there */
+    public void testWatchdogdDomain() throws DeviceNotAvailableException {
+        assertDomainZeroOrOne("u:r:watchdogd:s0", "/sbin/watchdogd");
+    }
+
+    /* logd may or may not be there */
+    public void testLogdDomain() throws DeviceNotAvailableException {
+        assertDomainZeroOrOne("u:r:logd:s0", "/system/bin/logd");
+    }
+
+    /* lmkd may or may not be there */
+    public void testLmkdDomain() throws DeviceNotAvailableException {
+        assertDomainZeroOrOne("u:r:lmkd:s0", "/system/bin/lmkd");
+    }
+
+    /* Wifi may be off so cardinality of 0 or 1 is ok */
+    public void testWpaDomain() throws DeviceNotAvailableException {
+        assertDomainZeroOrOne("u:r:wpa:s0", "/system/bin/wpa_supplicant");
+    }
+
+    /*
+     * Nothing should be running in this domain, cardinality test is all thats
+     * needed
+     */
+    public void testInitShellDomain() throws DeviceNotAvailableException {
+        assertDomainEmpty("u:r:init_shell:s0");
+    }
+
+    /*
+     * Nothing should be running in this domain, cardinality test is all thats
+     * needed
+     */
+    public void testRecoveryDomain() throws DeviceNotAvailableException {
+        assertDomainEmpty("u:r:recovery:s0");
+    }
+
+    /*
+     * Nothing should be running in this domain, cardinality test is all thats
+     * needed
+     */
+    public void testSuDomain() throws DeviceNotAvailableException {
+        assertDomainEmpty("u:r:su:s0");
+    }
+
+    /*
+     * All kthreads should be in kernel context.
+     */
+    public void testKernelDomain() throws DeviceNotAvailableException {
+        String domain = "u:r:kernel:s0";
+        List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
+        if (procs != null) {
+            for (ProcessDetails p : procs) {
+                assertTrue("Non Kernel thread \"" + p + "\" found!", p.isKernel());
+            }
+        }
+    }
+
+    private static class ProcessDetails {
+        public String label;
+        public String user;
+        public int pid;
+        public int ppid;
+        public String procTitle;
+
+        private static HashMap<String, ArrayList<ProcessDetails>> procMap;
+        private static HashMap<String, ArrayList<ProcessDetails>> exeMap;
+        private static int kernelParentThreadpid = -1;
+
+        ProcessDetails(String label, String user, int pid, int ppid, String procTitle) {
+            this.label = label;
+            this.user = user;
+            this.pid = pid;
+            this.ppid = ppid;
+            this.procTitle = procTitle;
+        }
+
+        @Override
+        public String toString() {
+            return "label: " + label
+                    + " user: " + user
+                    + " pid: " + pid
+                    + " ppid: " + ppid
+                    + " cmd: " + procTitle;
+        }
+
+
+        private static void createProcMap(ITestDevice tDevice) throws DeviceNotAvailableException {
+
+            /* take the output of a ps -Z to do our analysis */
+            CollectingOutputReceiver psOut = new CollectingOutputReceiver();
+            // TODO: remove "toybox" below and just run "ps"
+            tDevice.executeShellCommand("toybox ps -A -o label,user,pid,ppid,cmdline", psOut);
+            String psOutString = psOut.getOutput();
+            Pattern p = Pattern.compile(
+                    "^([\\w_:]+)\\s+([\\w_]+)\\s+(\\d+)\\s+(\\d+)\\s+(\\p{Graph}+)$",
+                    Pattern.MULTILINE);
+            Matcher m = p.matcher(psOutString);
+            procMap = new HashMap<String, ArrayList<ProcessDetails>>();
+            exeMap = new HashMap<String, ArrayList<ProcessDetails>>();
+            while(m.find()) {
+                String domainLabel = m.group(1);
+                String user = m.group(2);
+                int pid = Integer.parseInt(m.group(3));
+                int ppid = Integer.parseInt(m.group(4));
+                String procTitle = m.group(5);
+                ProcessDetails proc = new ProcessDetails(domainLabel, user, pid, ppid, procTitle);
+                if (procMap.get(domainLabel) == null) {
+                    procMap.put(domainLabel, new ArrayList<ProcessDetails>());
+                }
+                procMap.get(domainLabel).add(proc);
+                if (procTitle.equals("[kthreadd]") && ppid == 0) {
+                    kernelParentThreadpid = pid;
+                }
+                if (exeMap.get(procTitle) == null) {
+                    exeMap.put(procTitle, new ArrayList<ProcessDetails>());
+                }
+                exeMap.get(procTitle).add(proc);
+            }
+        }
+
+        public static HashMap<String, ArrayList<ProcessDetails>> getProcMap(ITestDevice tDevice)
+                throws DeviceNotAvailableException{
+            if (procMap == null) {
+                createProcMap(tDevice);
+            }
+            return procMap;
+        }
+
+        public static HashMap<String, ArrayList<ProcessDetails>> getExeMap(ITestDevice tDevice)
+                throws DeviceNotAvailableException{
+            if (exeMap == null) {
+                createProcMap(tDevice);
+            }
+            return exeMap;
+        }
+
+        public boolean isKernel() {
+            return (pid == kernelParentThreadpid || ppid == kernelParentThreadpid);
+        }
+    }
+}
diff --git a/hostsidetests/services/Android.mk b/hostsidetests/services/Android.mk
new file mode 100644
index 0000000..178cb8a
--- /dev/null
+++ b/hostsidetests/services/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/hostsidetests/services/activitymanager/Android.mk b/hostsidetests/services/activitymanager/Android.mk
new file mode 100644
index 0000000..35d34da
--- /dev/null
+++ b/hostsidetests/services/activitymanager/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Must match the package name in CtsTestCaseList.mk
+LOCAL_MODULE := CtsServicesHostTestCases
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+
+LOCAL_CTS_TEST_PACKAGE := android.server
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+# Build the test APKs using their own makefiles
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/services/activitymanager/AndroidTest.xml b/hostsidetests/services/activitymanager/AndroidTest.xml
new file mode 100644
index 0000000..ce407a3
--- /dev/null
+++ b/hostsidetests/services/activitymanager/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Sample host test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsDeviceServicesTestApp.apk" />
+    </target_preparer>
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsServicesHostTestCases.jar" />
+    </test>
+</configuration>
diff --git a/hostsidetests/services/activitymanager/OldAndroidTest.xml b/hostsidetests/services/activitymanager/OldAndroidTest.xml
new file mode 100644
index 0000000..37393763
--- /dev/null
+++ b/hostsidetests/services/activitymanager/OldAndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="CTS package preparer for install/uninstall of the apk used as a test operation target">
+    <include name="common-config" />
+    <!-- This will tell tradefed to install the test apk. -->
+    <option name="cts-apk-installer:test-file-name" value="CtsDeviceServicesTestApp.apk" />
+</configuration>
diff --git a/hostsidetests/services/activitymanager/app/Android.mk b/hostsidetests/services/activitymanager/app/Android.mk
new file mode 100644
index 0000000..4633ce2
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_PACKAGE_NAME := CtsDeviceServicesTestApp
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/services/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activitymanager/app/AndroidManifest.xml
new file mode 100755
index 0000000..32dba48
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.server.app">
+
+    <application>
+        <activity android:name=".TestActivity"
+                android:resizeable="true"
+                android:exported="true"
+        />
+        <activity android:name=".LaunchToSideActivity"
+                android:resizeable="true"
+                android:exported="true"
+        />
+        <activity android:name=".PipActivity"
+                android:resizeable="true"
+                android:supportsPictureInPicture="true"
+                android:exported="true"
+        />
+    </application>
+</manifest>
+
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchToSideActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchToSideActivity.java
new file mode 100644
index 0000000..31c169e
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchToSideActivity.java
@@ -0,0 +1,24 @@
+package android.server.app;
+
+import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public class LaunchToSideActivity extends Activity {
+    private static final String TAG = "LaunchToSide";
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        final Bundle extras = intent.getExtras();
+         if (extras != null && extras.getBoolean("launch_to_the_side")) {
+            Intent newIntent = new Intent("android.settings.SETTINGS");
+            newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_LAUNCH_TO_SIDE);
+            startActivity(newIntent);
+        }
+    }
+}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java
new file mode 100644
index 0000000..8a89deb
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 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.server.app;
+
+import android.app.Activity;
+
+public class PipActivity extends Activity {
+    @Override
+    protected void onResume() {
+        super.onResume();
+        enterPictureInPictureMode();
+    }
+}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java
new file mode 100644
index 0000000..222cdde
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 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.server.app;
+
+import android.app.Activity;
+
+public class TestActivity extends Activity {
+}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTests.java
new file mode 100644
index 0000000..aed23d8
--- /dev/null
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTests.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2015 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.server.cts;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import java.util.HashSet;
+
+public class ActivityManagerTests extends DeviceTestCase {
+
+    // Constants copied from ActivityManager.StackId. If they are changed there, these must be
+    // updated.
+    /** First static stack ID. */
+    public static final int FIRST_STATIC_STACK_ID = 0;
+
+    /** Home activity stack ID. */
+    public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;
+
+    /** ID of stack where fullscreen activities are normally launched into. */
+    public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
+
+    /** ID of stack where freeform/resized activities are normally launched into. */
+    public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
+
+    /** ID of stack that occupies a dedicated region of the screen. */
+    public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;
+
+    /** ID of stack that always on top (always visible) when it exist. */
+    public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
+
+    private static final String STACK_ID_PREFIX = "Stack id=";
+    private static final String TASK_ID_PREFIX = "taskId";
+
+    private static final String TEST_ACTIVITY_NAME = "TestActivity";
+    private static final String LAUNCH_TO_SIDE_ACTIVITY_NAME = "LaunchToSideActivity";
+    private static final String PIP_ACTIVITY_NAME = "PipActivity";
+
+    private static final String AM_STACK_LIST = "am stack list";
+    private static final String AM_START_TEST_ACTIVITY =
+            "am start -n android.server.app/." + TEST_ACTIVITY_NAME;
+    private static final String AM_START_LAUNCH_TO_SIDE_ACTIVITY =
+            "am start -n android.server.app/." + LAUNCH_TO_SIDE_ACTIVITY_NAME;
+    private static final String AM_START_PIP_ACTIVITY =
+            "am start -n android.server.app/." + PIP_ACTIVITY_NAME;
+    private static final String AM_FORCE_STOP_TEST = "am force-stop android.server.app";
+    private static final String AM_FORCE_STOP_SETTINGS = "com.android.settings";
+    private static final String AM_MOVE_TASK = "am stack movetask ";
+
+    /** A reference to the device under test. */
+    private ITestDevice mDevice;
+
+    private HashSet<String> mAvailableFeatures;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Get the device, this gives a handle to run commands and install APKs.
+        mDevice = getDevice();
+    }
+
+    @Override
+    protected void tearDown() {
+        try {
+            mDevice.executeShellCommand(AM_FORCE_STOP_TEST);
+            mDevice.executeShellCommand(AM_FORCE_STOP_SETTINGS);
+        } catch (DeviceNotAvailableException e) {
+        }
+    }
+
+    public void testStackList() throws Exception {
+        mDevice.executeShellCommand(AM_START_TEST_ACTIVITY);
+        HashSet<Integer> stacks = collectStacks();
+        assertTrue("At least two stacks expected, home and fullscreen.", stacks.size() >= 2);
+        assertTrue("Stacks must contain home stack.", stacks.contains(HOME_STACK_ID));
+        assertTrue("Stacks must contain fullscreen stack.", stacks.contains(
+                FULLSCREEN_WORKSPACE_STACK_ID));
+    }
+
+    // Utility method for debugging, not used directly here, but useful, so kept around.
+    private void printStacksAndTasks() throws DeviceNotAvailableException {
+        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
+        String output = outputReceiver.getOutput();
+        for (String line : output.split("\\n")) {
+            CLog.logAndDisplay(LogLevel.INFO, line);
+        }
+    }
+
+    private int getActivityTaskId(String name) throws DeviceNotAvailableException {
+        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
+        final String output = outputReceiver.getOutput();
+        for (String line : output.split("\\n")) {
+            if (line.contains(name)) {
+                for (String word : line.split("\\s+")) {
+                    if (word.startsWith(TASK_ID_PREFIX)) {
+                        final String withColon = word.split("=")[1];
+                        return Integer.parseInt(withColon.substring(0, withColon.length() - 1));
+                    }
+                }
+            }
+        }
+        return -1;
+    }
+
+    public void testDockActivity() throws Exception {
+        mDevice.executeShellCommand(AM_START_TEST_ACTIVITY);
+        final int taskId = getActivityTaskId(TEST_ACTIVITY_NAME);
+        final String cmd = AM_MOVE_TASK + taskId + " " + DOCKED_STACK_ID + " true";
+        mDevice.executeShellCommand(cmd);
+        HashSet<Integer> stacks = collectStacks();
+        assertTrue("At least two stacks expected, home and docked.", stacks.size() >= 2);
+        assertTrue("Stacks must contain home stack.", stacks.contains(HOME_STACK_ID));
+        assertTrue("Stacks must contain docked stack.", stacks.contains(DOCKED_STACK_ID));
+    }
+
+    public void testLaunchToSide() throws Exception {
+        mDevice.executeShellCommand(AM_START_LAUNCH_TO_SIDE_ACTIVITY);
+        final int taskId = getActivityTaskId(LAUNCH_TO_SIDE_ACTIVITY_NAME);
+        final String cmd = AM_MOVE_TASK + taskId + " " + DOCKED_STACK_ID + " true";
+        mDevice.executeShellCommand(cmd);
+        printStacksAndTasks();
+        mDevice.executeShellCommand(AM_START_LAUNCH_TO_SIDE_ACTIVITY
+                + " -f 0x20000000 --ez launch_to_the_side true");
+        HashSet<Integer> stacks = collectStacks();
+        assertTrue("At least two stacks expected, docked and fullscreen.", stacks.size() >= 2);
+        assertTrue("Stacks must contain fullscreen stack.", stacks.contains(
+                FULLSCREEN_WORKSPACE_STACK_ID));
+        assertTrue("Stacks must contain docked stack.", stacks.contains(DOCKED_STACK_ID));
+    }
+
+    public void testEnterPictureInPictureMode() throws Exception {
+        final boolean supportsPip = hasDeviceFeature("android.software.picture_in_picture");
+        mDevice.executeShellCommand(AM_START_PIP_ACTIVITY);
+        final HashSet<Integer> stacks = collectStacks();
+        final boolean containsPinnedStack = stacks.contains(PINNED_STACK_ID);
+        if (supportsPip) {
+            assertTrue("Stacks must contain pinned stack.", containsPinnedStack);
+        } else {
+            assertFalse("Stacks must not contain pinned stack.", containsPinnedStack);
+        }
+    }
+
+    private HashSet<Integer> collectStacks() throws DeviceNotAvailableException {
+        final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
+        final String output = outputReceiver.getOutput();
+        HashSet<Integer> stacks = new HashSet<>();
+        for (String line : output.split("\\n")) {
+            CLog.logAndDisplay(LogLevel.INFO, line);
+            if (line.startsWith(STACK_ID_PREFIX)) {
+                final String sub = line.substring(STACK_ID_PREFIX.length());
+                final int index = sub.indexOf(" ");
+                final int currentStack = Integer.parseInt(sub.substring(0, index));
+                stacks.add(currentStack);
+            }
+        }
+        return stacks;
+    }
+
+    private boolean hasDeviceFeature(String requiredFeature) throws DeviceNotAvailableException {
+        if (mAvailableFeatures == null) {
+            // TODO: Move this logic to ITestDevice.
+            String command = "pm list features";
+            String commandOutput = mDevice.executeShellCommand(command);
+            CLog.i("Output for command " + command + ": " + commandOutput);
+
+            // Extract the id of the new user.
+            mAvailableFeatures = new HashSet<>();
+            for (String feature: commandOutput.split("\\s+")) {
+                // Each line in the output of the command has the format "feature:{FEATURE_VALUE}".
+                String[] tokens = feature.split(":");
+                assertTrue("\"" + feature + "\" expected to have format feature:{FEATURE_VALUE}",
+                        tokens.length > 1);
+                assertEquals(feature, "feature", tokens[0]);
+                mAvailableFeatures.add(tokens[1]);
+            }
+        }
+        boolean result = mAvailableFeatures.contains(requiredFeature);
+        if (!result) {
+            CLog.logAndDisplay(LogLevel.INFO, "Device doesn't have required feature "
+                    + requiredFeature + ". Test won't run.");
+        }
+        return result;
+    }
+}
diff --git a/hostsidetests/theme/Android.mk b/hostsidetests/theme/Android.mk
index 188bf7a..3d27270 100644
--- a/hostsidetests/theme/Android.mk
+++ b/hostsidetests/theme/Android.mk
@@ -27,10 +27,15 @@
 
 LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
 
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+
 LOCAL_CTS_TEST_PACKAGE := android.host.theme
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/theme/AndroidTest.xml b/hostsidetests/theme/AndroidTest.xml
new file mode 100644
index 0000000..516df3d
--- /dev/null
+++ b/hostsidetests/theme/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Theme host test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsThemeDeviceApp.apk" />
+    </target_preparer>
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsThemeHostTestCases.jar" />
+    </test>
+</configuration>
diff --git a/hostsidetests/theme/app/Android.mk b/hostsidetests/theme/app/Android.mk
index 1be2983..7278a5b 100644
--- a/hostsidetests/theme/app/Android.mk
+++ b/hostsidetests/theme/app/Android.mk
@@ -36,6 +36,9 @@
 
 LOCAL_PACKAGE_NAME := CtsThemeDeviceApp
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_CTS_PACKAGE)
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
index b4bb748..30b0337 100644
--- a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
+++ b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
@@ -16,9 +16,8 @@
 
 package android.theme.cts;
 
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
-import com.android.cts.util.TimeoutReq;
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.cts.migration.MigrationHelper;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.build.IBuildInfo;
@@ -73,7 +72,7 @@
     private IAbi mAbi;
 
     /** A reference to the build. */
-    private CtsBuildHelper mBuild;
+    private IBuildInfo mBuildInfo;
 
     /** A reference to the device under test. */
     private ITestDevice mDevice;
@@ -89,8 +88,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        // Get the build, this is used to access the APK.
-        mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+        mBuildInfo = buildInfo;
     }
 
     @Override
@@ -101,14 +99,13 @@
         mDevice.uninstallPackage(APP_PACKAGE_NAME);
 
         // Get the APK from the build.
-        final File app = mBuild.getTestApp(String.format("%s.apk", APK_NAME));
+        final File app = MigrationHelper.getTestFile(mBuildInfo, String.format("%s.apk", APK_NAME));
         final String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
 
         mDevice.installPackage(app, false, options);
 
         final String density = getDensityBucketForDevice(mDevice);
         final String zipFile = String.format("/%s.zip", density);
-        Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Loading resources from " + zipFile);
 
         final InputStream zipStream = ThemeHostTest.class.getResourceAsStream(zipFile);
         if (zipStream != null) {
@@ -162,7 +159,6 @@
         super.tearDown();
     }
 
-    @TimeoutReq(minutes = 60)
     public void testThemes() throws Exception {
         if (checkHardwareTypeSkipTest(mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim())) {
             Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Skipped themes test for watch");
@@ -174,8 +170,6 @@
             return;
         }
 
-        Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Generating device images...");
-
         assertTrue("Aborted image generation", generateDeviceImages());
 
         // Pull ZIP file from remote device.
@@ -184,8 +178,6 @@
 
         int numTasks = 0;
 
-        Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Extracting generated images...");
-
         // Extract generated images to temporary files.
         final byte[] data = new byte[4096];
         final ZipInputStream zipInput = new ZipInputStream(new FileInputStream(localZip));
@@ -216,16 +208,12 @@
 
         zipInput.close();
 
-        Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Waiting for comparison tasks...");
-
         int failures = 0;
         for (int i = numTasks; i > 0; i--) {
             failures += mCompletionService.take().get() ? 0 : 1;
         }
 
         assertTrue(failures + " failures in theme test", failures == 0);
-
-        Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Finished!");
     }
 
     private boolean generateDeviceImages() throws Exception {
@@ -238,8 +226,6 @@
         // Start activity
         mDevice.executeShellCommand(START_CMD);
 
-        Log.logAndDisplay(LogLevel.VERBOSE, LOG_TAG, "Starting image generation...");
-
         boolean aborted = false;
         boolean waiting = true;
         do {
@@ -272,8 +258,6 @@
             in.close();
         } while (waiting && !aborted);
 
-        Log.logAndDisplay(LogLevel.VERBOSE, LOG_TAG, "Image generation completed!");
-
         return !aborted;
     }
 
diff --git a/hostsidetests/ui/Android.mk b/hostsidetests/ui/Android.mk
new file mode 100644
index 0000000..b0de7fc
--- /dev/null
+++ b/hostsidetests/ui/Android.mk
@@ -0,0 +1,40 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := CtsUiHostTestCases
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+$(COMPATIBILITY_TESTCASES_OUT_cts_v2)/CtsUiHostTestCases.jar : $(COMPATIBILITY_TESTCASES_OUT_cts_v2)/com.replica.replicaisland.apk
+
+LOCAL_CTS_TEST_PACKAGE := android.ui.cts
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/ui/AndroidTest.xml b/hostsidetests/ui/AndroidTest.xml
new file mode 100644
index 0000000..7d17e2b
--- /dev/null
+++ b/hostsidetests/ui/AndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS UI host test cases">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsUiHostTestCases.jar" />
+        <option name="runtime-hint" value="2m" />
+    </test>
+</configuration>
diff --git a/hostsidetests/ui/appA/Android.mk b/hostsidetests/ui/appA/Android.mk
new file mode 100644
index 0000000..41bffeb
--- /dev/null
+++ b/hostsidetests/ui/appA/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsDeviceTaskSwitchingAppA
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/ui/appA/AndroidManifest.xml b/hostsidetests/ui/appA/AndroidManifest.xml
new file mode 100644
index 0000000..f336abd
--- /dev/null
+++ b/hostsidetests/ui/appA/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.taskswitching.appa">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+
+    <application>
+        <activity
+            android:name=".AppAActivity"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
+            android:screenOrientation="portrait" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/hostsidetests/ui/appA/src/android/taskswitching/appa/AppAActivity.java b/hostsidetests/ui/appA/src/android/taskswitching/appa/AppAActivity.java
new file mode 100644
index 0000000..32ccfc1
--- /dev/null
+++ b/hostsidetests/ui/appA/src/android/taskswitching/appa/AppAActivity.java
@@ -0,0 +1,65 @@
+/*
+ * 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 android.taskswitching.appa;
+
+import android.app.ListActivity;
+import android.content.Intent;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.WindowManager;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+/**
+ * Simple activity to notify completion via broadcast after onResume.
+ * This is for measuring taskswitching time between two apps.
+ */
+public class AppAActivity extends ListActivity {
+    static final String TAG = "AppAActivity";
+    private static final int NUMBER_ELEMENTS = 1000;
+    private static final String TASKSWITCHING_INTENT = "android.taskswitching.appa";
+    private Handler mHandler;
+
+    private String[] mItems = new String[NUMBER_ELEMENTS];
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        for (int i = 0; i < NUMBER_ELEMENTS; i++) {
+            mItems[i] = "A" + Integer.toString(i);
+        }
+        setListAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, mItems));
+        ListView view = getListView();
+        mHandler = new Handler();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mHandler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                Intent intent = new Intent(TASKSWITCHING_INTENT);
+                sendBroadcast(intent);
+            }
+        });
+    }
+}
diff --git a/hostsidetests/ui/appB/Android.mk b/hostsidetests/ui/appB/Android.mk
new file mode 100644
index 0000000..3b9cdae
--- /dev/null
+++ b/hostsidetests/ui/appB/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsDeviceTaskSwitchingAppB
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/ui/appB/AndroidManifest.xml b/hostsidetests/ui/appB/AndroidManifest.xml
new file mode 100644
index 0000000..aaf7a2c
--- /dev/null
+++ b/hostsidetests/ui/appB/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.taskswitching.appb">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+
+    <application>
+        <activity
+            android:name=".AppBActivity"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
+            android:screenOrientation="portrait" >
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/hostsidetests/ui/appB/src/android/taskswitching/appb/AppBActivity.java b/hostsidetests/ui/appB/src/android/taskswitching/appb/AppBActivity.java
new file mode 100644
index 0000000..ea7f52a
--- /dev/null
+++ b/hostsidetests/ui/appB/src/android/taskswitching/appb/AppBActivity.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 android.taskswitching.appb;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.WindowManager;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+/**
+ * Simple activity to notify completion via broadcast after onResume.
+ * This is for measuring taskswitching time between two apps.
+ */
+public class AppBActivity extends ListActivity {
+    static final String TAG = "AppBActivity";
+    private static final int NUMBER_ELEMENTS = 1000;
+    private static final String TASKSWITCHING_INTENT = "android.taskswitching.appb";
+    private Handler mHandler;
+
+    private String[] mItems = new String[NUMBER_ELEMENTS];
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        for (int i = 0; i < NUMBER_ELEMENTS; i++) {
+            mItems[i] = "B" + Integer.toString(i);
+        }
+        setListAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, mItems));
+        ListView view = getListView();
+        mHandler = new Handler();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mHandler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                Intent intent = new Intent(TASKSWITCHING_INTENT);
+                sendBroadcast(intent);
+            }
+        });
+    }
+}
diff --git a/hostsidetests/ui/control/Android.mk b/hostsidetests/ui/control/Android.mk
new file mode 100644
index 0000000..e1ff237
--- /dev/null
+++ b/hostsidetests/ui/control/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsDeviceTaskSwitchingControl
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/ui/control/AndroidManifest.xml b/hostsidetests/ui/control/AndroidManifest.xml
new file mode 100644
index 0000000..fd48287
--- /dev/null
+++ b/hostsidetests/ui/control/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.taskswitching.control.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation
+        android:targetPackage="android.taskswitching.control.cts"
+        android:name="android.support.test.runner.AndroidJUnitRunner" >
+        <meta-data
+            android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+</manifest>
diff --git a/hostsidetests/ui/control/src/android/taskswitching/control/cts/TaskSwitchingDeviceTest.java b/hostsidetests/ui/control/src/android/taskswitching/control/cts/TaskSwitchingDeviceTest.java
new file mode 100644
index 0000000..13b60be
--- /dev/null
+++ b/hostsidetests/ui/control/src/android/taskswitching/control/cts/TaskSwitchingDeviceTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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 android.taskswitching.control.cts;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import android.cts.util.CtsAndroidTestCase;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.MeasureRun;
+import com.android.compatibility.common.util.MeasureTime;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+
+/**
+ * Device test which actually launches two apps sequentially and
+ * measure time for switching.
+ * Completion of launch is notified via broadcast.
+ */
+public class TaskSwitchingDeviceTest extends CtsAndroidTestCase {
+    private static final String PKG_A = "android.taskswitching.appa";
+    private static final String PKG_B = "android.taskswitching.appb";
+    private static final String ACTIVITY_A = "AppAActivity";
+    private static final String ACTIVITY_B = "AppBActivity";
+    private static final long TASK_SWITCHING_WAIT_TIME = 5;
+    private final AppBroadcastReceiver mReceiverA = new AppBroadcastReceiver();
+    private final AppBroadcastReceiver mReceiverB = new AppBroadcastReceiver();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        startActivity(PKG_A, ACTIVITY_A);
+        startActivity(PKG_B, ACTIVITY_B);
+        IntentFilter filterA = new IntentFilter();
+        filterA.addAction(PKG_A);
+        IntentFilter filterB = new IntentFilter();
+        filterB.addAction(PKG_B);
+        getContext().registerReceiver(mReceiverA, filterA);
+        getContext().registerReceiver(mReceiverB, filterB);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        getContext().unregisterReceiver(mReceiverA);
+        getContext().unregisterReceiver(mReceiverB);
+        super.tearDown();
+    }
+
+    public void testMeasureTaskSwitching() throws Exception {
+        final int NUMBER_REPEAT = 10;
+        final int SWITCHING_PER_ONE_TRY = 10;
+
+        double[] results = MeasureTime.measure(NUMBER_REPEAT, new MeasureRun() {
+
+            @Override
+            public void run(int i) throws Exception {
+                for (int j = 0; j < SWITCHING_PER_ONE_TRY; j++) {
+                    startActivity(PKG_A, ACTIVITY_A);
+                    assertTrue(mReceiverA.waitForBroadcast(TASK_SWITCHING_WAIT_TIME));
+                    startActivity(PKG_B, ACTIVITY_B);
+                    assertTrue(mReceiverB.waitForBroadcast(TASK_SWITCHING_WAIT_TIME));
+                }
+            }
+        });
+        DeviceReportLog report = new DeviceReportLog();
+        report.addValues("task switching time", results, ResultType.LOWER_BETTER, ResultUnit.MS);
+        Stat.StatResult stat = Stat.getStat(results);
+        report.setSummary("task switching time", stat.mAverage,
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.submit(getInstrumentation());
+    }
+
+    private void startActivity(String packageName, String activityName) {
+        Context context = getContext();
+        Intent intent = new Intent();
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        intent.setComponent(new ComponentName(packageName, packageName + "." + activityName));
+        context.startActivity(intent);
+    }
+
+    class AppBroadcastReceiver extends BroadcastReceiver {
+        private final Semaphore mSemaphore = new Semaphore(0);
+
+        public boolean waitForBroadcast(long timeoutInSec) throws InterruptedException {
+            return mSemaphore.tryAcquire(timeoutInSec, TimeUnit.SECONDS);
+        }
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mSemaphore.release();
+        }
+    }
+}
diff --git a/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java b/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
new file mode 100644
index 0000000..d91944a
--- /dev/null
+++ b/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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 android.ui.cts;
+
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.compatibility.common.util.MeasureRun;
+import com.android.compatibility.common.util.MeasureTime;
+import com.android.compatibility.common.util.MetricsReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+import com.android.cts.migration.MigrationHelper;
+import com.android.ddmlib.Log;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.File;
+
+/**
+ * Test to measure installation time of a APK.
+ */
+public class InstallTimeTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+    private IBuildInfo mBuild;
+    private ITestDevice mDevice;
+    private IAbi mAbi;
+
+    private static final String TAG = "InstallTimeTest";
+    static final String PACKAGE = "com.replica.replicaisland";
+    static final String APK = "com.replica.replicaisland.apk";
+    private static final double OUTLIER_THRESHOLD = 0.1;
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mBuild = buildInfo;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDevice = getDevice();
+    }
+
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDevice.uninstallPackage(PACKAGE);
+        super.tearDown();
+    }
+
+    public void testInstallTime() throws Exception {
+        MetricsReportLog report = new MetricsReportLog(mDevice.getSerialNumber(), mAbi.getName(),
+                String.format("%s#%s", getClass().getName(), "testInstallTime"));
+        final int NUMBER_REPEAT = 10;
+        final IBuildInfo build = mBuild;
+        final ITestDevice device = mDevice;
+        double[] result = MeasureTime.measure(NUMBER_REPEAT, new MeasureRun() {
+            @Override
+            public void prepare(int i) throws Exception {
+                device.uninstallPackage(PACKAGE);
+            }
+            @Override
+            public void run(int i) throws Exception {
+                File app = MigrationHelper.getTestFile(build, APK);
+                String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+                device.installPackage(app, false, options);
+            }
+        });
+        report.addValues("install time", result, ResultType.LOWER_BETTER, ResultUnit.MS);
+        Stat.StatResult stat = Stat.getStatWithOutlierRejection(result, OUTLIER_THRESHOLD);
+        if (stat.mDataCount != result.length) {
+            Log.w(TAG, "rejecting " + (result.length - stat.mDataCount) + " outliers");
+        }
+        report.setSummary("install time", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.submit();
+    }
+
+}
diff --git a/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java b/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
new file mode 100644
index 0000000..4af40a2
--- /dev/null
+++ b/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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 android.ui.cts;
+
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.compatibility.common.util.MetricsStore;
+import com.android.compatibility.common.util.ReportLog;
+import com.android.cts.migration.MigrationHelper;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.ddmlib.testrunner.TestRunResult;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Measure time to taskswitching between two Apps: A & B
+ * Actual test is done in device, but this host side code installs all necessary APKs
+ * and starts device test which is in CtsDeviceTaskswitchingControl.
+ */
+public class TaskSwitchingTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+    private static final String TAG = "TaskSwitchingTest";
+    private final static String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
+    private static final String RESULT_KEY = "COMPATIBILITY_TEST_RESULT";
+    private IBuildInfo mBuild;
+    private ITestDevice mDevice;
+    private ReportLog mReport = null;
+    private IAbi mAbi;
+
+    static final String[] PACKAGES = {
+        "android.taskswitching.control.cts",
+        "android.taskswitching.appa",
+        "android.taskswitching.appb"
+    };
+    static final String[] APKS = {
+        "CtsDeviceTaskSwitchingControl.apk",
+        "CtsDeviceTaskSwitchingAppA.apk",
+        "CtsDeviceTaskSwitchingAppB.apk"
+    };
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mBuild = buildInfo;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDevice = getDevice();
+        String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+        for (int i = 0; i < PACKAGES.length; i++) {
+            mDevice.uninstallPackage(PACKAGES[i]);
+            File app = MigrationHelper.getTestFile(mBuild, APKS[i]);
+            mDevice.installPackage(app, false, options);
+        }
+    }
+
+
+    @Override
+    protected void tearDown() throws Exception {
+        for (int i = 0; i < PACKAGES.length; i++) {
+            mDevice.uninstallPackage(PACKAGES[i]);
+        }
+        super.tearDown();
+    }
+
+    public void testTaskSwitching() throws Exception {
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(PACKAGES[0], RUNNER,
+                mDevice.getIDevice());
+        LocalListener listener = new LocalListener();
+        mDevice.runInstrumentationTests(testRunner, listener);
+        TestRunResult result = listener.getCurrentRunResults();
+        if (result.isRunFailure()) {
+            fail(result.getRunFailureMessage());
+        }
+        assertNotNull("no performance data", mReport);
+        MetricsStore.storeResult(mDevice.getSerialNumber(), mAbi.getName(),
+                String.format("%s#%s", getClass().getName(), "testTaskSwitching"), mReport);
+
+    }
+
+    public class LocalListener extends CollectingTestListener {
+        @Override
+        public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
+            // necessary as testMetrics passed from CollectingTestListerner is empty
+            if (testMetrics.containsKey(RESULT_KEY)) {
+                try {
+                    mReport = ReportLog.parse(testMetrics.get(RESULT_KEY));
+                } catch (XmlPullParserException | IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            super.testEnded(test, testMetrics);
+        }
+    }
+}
diff --git a/hostsidetests/usage/Android.mk b/hostsidetests/usage/Android.mk
index 1d4e36d..203b684 100644
--- a/hostsidetests/usage/Android.mk
+++ b/hostsidetests/usage/Android.mk
@@ -19,12 +19,15 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Must match the package name in CtsTestCaseList.mk
-LOCAL_MODULE := CtsUsageHostTestCases
+LOCAL_MODULE := CtsAppUsageHostTestCases
 
 LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
 
 LOCAL_CTS_TEST_PACKAGE := android.host.app.usage
 
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/usage/AndroidTest.xml b/hostsidetests/usage/AndroidTest.xml
new file mode 100644
index 0000000..bba2748
--- /dev/null
+++ b/hostsidetests/usage/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS App Usage host test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAppUsageTestApp.apk" />
+    </target_preparer>
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsAppUsageHostTestCases.jar" />
+    </test>
+</configuration>
diff --git a/hostsidetests/usage/app/Android.mk b/hostsidetests/usage/app/Android.mk
index b23efbc..31b6d8f 100644
--- a/hostsidetests/usage/app/Android.mk
+++ b/hostsidetests/usage/app/Android.mk
@@ -23,6 +23,9 @@
 
 LOCAL_SDK_VERSION := current
 
-LOCAL_PACKAGE_NAME := CtsDeviceAppUsageTestApp
+LOCAL_PACKAGE_NAME := CtsAppUsageTestApp
+
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/usage/app/AndroidManifest.xml b/hostsidetests/usage/app/AndroidManifest.xml
index bad453f..7d5ce48 100755
--- a/hostsidetests/usage/app/AndroidManifest.xml
+++ b/hostsidetests/usage/app/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.app.usage.test">
+    package="android.app.usage.app">
 
     <application>
         <activity android:name=".TestActivity">
diff --git a/hostsidetests/usage/app/src/android/app/usage/app/TestActivity.java b/hostsidetests/usage/app/src/android/app/usage/app/TestActivity.java
new file mode 100644
index 0000000..8cb5842
--- /dev/null
+++ b/hostsidetests/usage/app/src/android/app/usage/app/TestActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.usage.app;
+
+import android.app.Activity;
+
+public class TestActivity extends Activity {
+}
\ No newline at end of file
diff --git a/hostsidetests/usage/app/src/com/android/cts/app/usage/test/TestActivity.java b/hostsidetests/usage/app/src/com/android/cts/app/usage/test/TestActivity.java
deleted file mode 100644
index 9432477..0000000
--- a/hostsidetests/usage/app/src/com/android/cts/app/usage/test/TestActivity.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2015 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.app.usage.test;
-
-import android.app.Activity;
-
-public class TestActivity extends Activity {
-}
\ No newline at end of file
diff --git a/hostsidetests/usage/src/android/app/usage/cts/AppIdleHostTest.java b/hostsidetests/usage/src/android/app/usage/cts/AppIdleHostTest.java
new file mode 100644
index 0000000..3cd7bda
--- /dev/null
+++ b/hostsidetests/usage/src/android/app/usage/cts/AppIdleHostTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.usage.cts;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+public class AppIdleHostTest extends DeviceTestCase {
+    private static final String SETTINGS_APP_IDLE_CONSTANTS = "app_idle_constants";
+
+    private static final String TEST_APP_PACKAGE = "android.app.usage.app";
+    private static final String TEST_APP_CLASS = "TestActivity";
+
+    private static final long ACTIVITY_LAUNCH_WAIT_MILLIS = 500;
+
+    /**
+     * A reference to the device under test.
+     */
+    private ITestDevice mDevice;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Get the device, this gives a handle to run commands and install APKs.
+        mDevice = getDevice();
+    }
+
+    /**
+     * Checks whether an package is idle.
+     * @param appPackage The package to check for idleness.
+     * @return true if the package is idle
+     * @throws DeviceNotAvailableException
+     */
+    private boolean isAppIdle(String appPackage) throws DeviceNotAvailableException {
+        String result = mDevice.executeShellCommand(String.format("am get-inactive %s", appPackage));
+        return result.contains("Idle=true");
+    }
+
+    /**
+     * Set the app idle settings.
+     * @param settingsStr The settings string, a comma separated key=value list.
+     * @throws DeviceNotAvailableException
+     */
+    private void setAppIdleSettings(String settingsStr) throws DeviceNotAvailableException {
+        mDevice.executeShellCommand(String.format("settings put global %s \"%s\"",
+                SETTINGS_APP_IDLE_CONSTANTS, settingsStr));
+    }
+
+    /**
+     * Get the current app idle settings.
+     * @throws DeviceNotAvailableException
+     */
+    private String getAppIdleSettings() throws DeviceNotAvailableException {
+        String result = mDevice.executeShellCommand(String.format("settings get global %s",
+                SETTINGS_APP_IDLE_CONSTANTS));
+        return result.trim();
+    }
+
+    /**
+     * Launch the test app for a few hundred milliseconds then launch home.
+     * @throws DeviceNotAvailableException
+     */
+    private void startAndStopTestApp() throws DeviceNotAvailableException {
+        // Launch the app.
+        mDevice.executeShellCommand(
+                String.format("am start -W -a android.intent.action.MAIN -n %s/%s.%s",
+                        TEST_APP_PACKAGE, TEST_APP_PACKAGE, TEST_APP_CLASS));
+
+        // Wait for some time.
+        sleepUninterrupted(ACTIVITY_LAUNCH_WAIT_MILLIS);
+
+        // Launch home.
+        mDevice.executeShellCommand(
+                "am start -W -a android.intent.action.MAIN -c android.intent.category.HOME");
+    }
+
+    /**
+     * Tests that the app is not idle right after it is launched.
+     */
+    public void testAppIsNotIdleAfterBeingLaunched() throws Exception {
+        final String previousState = getAppIdleSettings();
+        try {
+            // Set the app idle time to something large.
+            setAppIdleSettings("idle_duration=10000,wallclock_threshold=10000");
+            startAndStopTestApp();
+            assertFalse(isAppIdle(TEST_APP_PACKAGE));
+        } finally {
+            setAppIdleSettings(previousState);
+        }
+    }
+
+    private static void sleepUninterrupted(long timeMillis) {
+        boolean interrupted;
+        do {
+            try {
+                Thread.sleep(timeMillis);
+                interrupted = false;
+            } catch (InterruptedException e) {
+                interrupted = true;
+            }
+        } while (interrupted);
+    }
+}
diff --git a/hostsidetests/usage/src/com/android/cts/app/usage/AppIdleHostTest.java b/hostsidetests/usage/src/com/android/cts/app/usage/AppIdleHostTest.java
deleted file mode 100644
index b94d086..0000000
--- a/hostsidetests/usage/src/com/android/cts/app/usage/AppIdleHostTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2015 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.app.usage;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-public class AppIdleHostTest extends DeviceTestCase implements IBuildReceiver {
-    private static final String SETTINGS_APP_IDLE_CONSTANTS = "app_idle_constants";
-
-    private static final String TEST_APP_PACKAGE = "com.android.cts.app.usage.test";
-    private static final String TEST_APP_APK = "CtsDeviceAppUsageTestApp.apk";
-    private static final String TEST_APP_CLASS = "TestActivity";
-
-    private static final long ACTIVITY_LAUNCH_WAIT_MILLIS = 500;
-
-    /**
-     * A reference to the build.
-     */
-    private CtsBuildHelper mBuild;
-
-    /**
-     * A reference to the device under test.
-     */
-    private ITestDevice mDevice;
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        // Get the build, this is used to access the APK.
-        mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // Get the device, this gives a handle to run commands and install APKs.
-        mDevice = getDevice();
-
-        // Remove any previously installed versions of this APK.
-        mDevice.uninstallPackage(TEST_APP_PACKAGE);
-
-        // Install the APK on the device.
-        mDevice.installPackage(mBuild.getTestApp(TEST_APP_APK), false);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        // Remove the package once complete.
-        mDevice.uninstallPackage(TEST_APP_PACKAGE);
-        super.tearDown();
-    }
-
-    /**
-     * Checks whether an package is idle.
-     * @param appPackage The package to check for idleness.
-     * @return true if the package is idle
-     * @throws DeviceNotAvailableException
-     */
-    private boolean isAppIdle(String appPackage) throws DeviceNotAvailableException {
-        String result = mDevice.executeShellCommand(String.format("am get-inactive %s", appPackage));
-        return result.contains("Idle=true");
-    }
-
-    /**
-     * Set the app idle settings.
-     * @param settingsStr The settings string, a comma separated key=value list.
-     * @throws DeviceNotAvailableException
-     */
-    private void setAppIdleSettings(String settingsStr) throws DeviceNotAvailableException {
-        mDevice.executeShellCommand(String.format("settings put global %s \"%s\"",
-                SETTINGS_APP_IDLE_CONSTANTS, settingsStr));
-    }
-
-    /**
-     * Get the current app idle settings.
-     * @throws DeviceNotAvailableException
-     */
-    private String getAppIdleSettings() throws DeviceNotAvailableException {
-        String result = mDevice.executeShellCommand(String.format("settings get global %s",
-                SETTINGS_APP_IDLE_CONSTANTS));
-        return result.trim();
-    }
-
-    /**
-     * Launch the test app for a few hundred milliseconds then launch home.
-     * @throws DeviceNotAvailableException
-     */
-    private void startAndStopTestApp() throws DeviceNotAvailableException {
-        // Launch the app.
-        mDevice.executeShellCommand(
-                String.format("am start -W -a android.intent.action.MAIN -n %s/%s.%s",
-                        TEST_APP_PACKAGE, TEST_APP_PACKAGE, TEST_APP_CLASS));
-
-        // Wait for some time.
-        sleepUninterrupted(ACTIVITY_LAUNCH_WAIT_MILLIS);
-
-        // Launch home.
-        mDevice.executeShellCommand(
-                "am start -W -a android.intent.action.MAIN -c android.intent.category.HOME");
-    }
-
-    /**
-     * Tests that the app is not idle right after it is launched.
-     */
-    public void testAppIsNotIdleAfterBeingLaunched() throws Exception {
-        final String previousState = getAppIdleSettings();
-        try {
-            // Set the app idle time to something large.
-            setAppIdleSettings("idle_duration=10000,wallclock_threshold=10000");
-            startAndStopTestApp();
-            assertFalse(isAppIdle(TEST_APP_PACKAGE));
-        } finally {
-            setAppIdleSettings(previousState);
-        }
-    }
-
-    private static void sleepUninterrupted(long timeMillis) {
-        boolean interrupted;
-        do {
-            try {
-                Thread.sleep(timeMillis);
-                interrupted = false;
-            } catch (InterruptedException e) {
-                interrupted = true;
-            }
-        } while (interrupted);
-    }
-}
diff --git a/hostsidetests/usb/Android.mk b/hostsidetests/usb/Android.mk
index f93dfa4..facc4d8 100644
--- a/hostsidetests/usb/Android.mk
+++ b/hostsidetests/usb/Android.mk
@@ -21,10 +21,15 @@
 
 LOCAL_MODULE := CtsUsbTests
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
 
 LOCAL_CTS_TEST_PACKAGE := android.usb
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 # Build the test APKs using their own makefiles
diff --git a/hostsidetests/usb/AndroidTest.xml b/hostsidetests/usb/AndroidTest.xml
new file mode 100644
index 0000000..013e97f
--- /dev/null
+++ b/hostsidetests/usb/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS USB host test cases">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsUsbTests.jar" />
+    </test>
+</configuration>
diff --git a/hostsidetests/usb/SerialTestApp/Android.mk b/hostsidetests/usb/SerialTestApp/Android.mk
index a8f51ad..80316b2 100644
--- a/hostsidetests/usb/SerialTestApp/Android.mk
+++ b/hostsidetests/usb/SerialTestApp/Android.mk
@@ -28,4 +28,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
index 3af52c0..5377711 100644
--- a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
+++ b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
@@ -15,8 +15,8 @@
  */
 package com.android.cts.usb;
 
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.cts.migration.MigrationHelper;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestRunResult;
 import com.android.tradefed.build.IBuildInfo;
@@ -45,7 +45,7 @@
     private static final String APK_NAME="CtsUsbSerialTestApp.apk";
     private ITestDevice mDevice;
     private IAbi mAbi;
-    private CtsBuildHelper mBuild;
+    private IBuildInfo mBuild;
 
     @Override
     public void setAbi(IAbi abi) {
@@ -54,7 +54,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+        mBuild = buildInfo;
     }
 
     @Override
@@ -62,7 +62,7 @@
         super.setUp();
         mDevice = getDevice();
         mDevice.uninstallPackage(PACKAGE_NAME);
-        File app = mBuild.getTestApp(APK_NAME);
+        File app = MigrationHelper.getTestFile(mBuild, APK_NAME);
         String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
         mDevice.installPackage(app, false, options);
     }
diff --git a/libs/commonutil/Android.mk b/libs/commonutil/Android.mk
deleted file mode 100644
index 9c131b0..0000000
--- a/libs/commonutil/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# 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.
-#
-
-include $(call all-subdir-makefiles)
-
-# ======================================================
-# Build a static host library for the AbiUtils
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := src/com/android/cts/util/AbiUtils.java
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := ctsabiutilslib
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/libs/commonutil/src/com/android/cts/util/AbiUtils.java b/libs/commonutil/src/com/android/cts/util/AbiUtils.java
deleted file mode 100644
index 42336f3..0000000
--- a/libs/commonutil/src/com/android/cts/util/AbiUtils.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.util;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Utility class for handling device ABIs
- */
-public class AbiUtils {
-
-    /**
-     * The set of 32Bit ABIs.
-     */
-    private static final Set<String> ABIS_32BIT = new HashSet<String>();
-
-    /**
-     * The set of 64Bit ABIs.
-     */
-    private static final Set<String> ABIS_64BIT = new HashSet<String>();
-
-    /**
-     * The set of ARM ABIs.
-     */
-    private static final Set<String> ARM_ABIS = new HashSet<String>();
-
-    /**
-     * The set of Intel ABIs.
-     */
-    private static final Set<String> INTEL_ABIS = new HashSet<String>();
-
-    /**
-     * The set of Mips ABIs.
-     */
-    private static final Set<String> MIPS_ABIS = new HashSet<String>();
-
-    /**
-     * The set of ABI names which CTS supports.
-     */
-    private static final Set<String> ABIS_SUPPORTED_BY_CTS = new HashSet<String>();
-
-    /**
-     * The map of architecture to ABI.
-     */
-    private static final Map<String, Set<String>> ARCH_TO_ABIS = new HashMap<String, Set<String>>();
-    static {
-        ABIS_32BIT.add("armeabi-v7a");
-        ABIS_32BIT.add("x86");
-        ABIS_32BIT.add("mips");
-
-        ABIS_64BIT.add("arm64-v8a");
-        ABIS_64BIT.add("x86_64");
-        ABIS_64BIT.add("mips64");
-
-        ARM_ABIS.add("armeabi-v7a");
-        ARM_ABIS.add("arm64-v8a");
-
-        INTEL_ABIS.add("x86");
-        INTEL_ABIS.add("x86_64");
-
-        MIPS_ABIS.add("mips");
-        MIPS_ABIS.add("mips64");
-
-        ARCH_TO_ABIS.put("arm", ARM_ABIS);
-        ARCH_TO_ABIS.put("arm64", ARM_ABIS);
-        ARCH_TO_ABIS.put("x86", INTEL_ABIS);
-        ARCH_TO_ABIS.put("x86_64", INTEL_ABIS);
-        ARCH_TO_ABIS.put("mips", MIPS_ABIS);
-        ARCH_TO_ABIS.put("mips64", MIPS_ABIS);
-
-        ABIS_SUPPORTED_BY_CTS.addAll(ARM_ABIS);
-        ABIS_SUPPORTED_BY_CTS.addAll(INTEL_ABIS);
-        ABIS_SUPPORTED_BY_CTS.addAll(MIPS_ABIS);
-    }
-
-    /**
-     * Private constructor to avoid instantiation.
-     */
-    private AbiUtils() {}
-
-    /**
-     * Returns the set of ABIs associated with the given architecture.
-     * @param arch The architecture to look up.
-     * @return a new Set containing the ABIs.
-     */
-    public static Set<String> getAbisForArch(String arch) {
-        if (arch == null || arch.isEmpty() || !ARCH_TO_ABIS.containsKey(arch)) {
-            return getAbisSupportedByCts();
-        }
-        return new HashSet<String>(ARCH_TO_ABIS.get(arch));
-    }
-
-    /**
-     * Returns the set of ABIs supported by CTS.
-     * @return a new Set containing the supported ABIs.
-     */
-    public static Set<String> getAbisSupportedByCts() {
-        return new HashSet<String>(ABIS_SUPPORTED_BY_CTS);
-    }
-
-    /**
-     * @param abi The ABI name to test.
-     * @return true if the given ABI is supported by CTS.
-     */
-    public static boolean isAbiSupportedByCts(String abi) {
-        return ABIS_SUPPORTED_BY_CTS.contains(abi);
-    }
-
-    /**
-     * Creates a flag for the given ABI.
-     * @param abi the ABI to create the flag for.
-     * @return a string which can be add to a command sent to ADB.
-     */
-    public static String createAbiFlag(String abi) {
-        if (abi == null || abi.isEmpty() || !isAbiSupportedByCts(abi)) {
-            return "";
-        }
-        return String.format("--abi %s ", abi);
-    }
-
-    /**
-     * Creates a unique id from the given ABI and name.
-     * @param abi The ABI to use.
-     * @param name The name to use.
-     * @return a string which uniquely identifies a run.
-     */
-    public static String createId(String abi, String name) {
-        return String.format("%s %s", abi, name);
-    }
-
-    /**
-     * Parses a unique id into the ABI and name.
-     * @param id The id to parse.
-     * @return a string array containing the ABI and name.
-     */
-    public static String[] parseId(String id) {
-        if (id == null || !id.contains(" ")) {
-            return new String[] {"", ""};
-        }
-        return id.split(" ");
-    }
-
-    /**
-     * @return the test name portion of the test id.
-     *         e.g. armeabi-v7a android.mytest = android.mytest
-     */
-    public static String parseTestName(String id) {
-        return parseId(id)[1];
-    }
-
-    /**
-     * @return the abi portion of the test id.
-     *         e.g. armeabi-v7a android.mytest = armeabi-v7a
-     */
-    public static String parseAbi(String id) {
-        return parseId(id)[0];
-    }
-
-    /**
-     * @param name The name of the ABI.
-     * @return The bitness of the ABI with the given name
-     */
-    public static String getBitness(String name) {
-        return ABIS_32BIT.contains(name) ? "32" : "64";
-    }
-
-    /**
-     * @param abilistString A comma separated string containing abis.
-     * @return A List of Strings containing valid ABIs.
-     */
-    public static Set<String> parseAbiList(String unsupportedAbiDescription) {
-        Set<String> abiSet = new HashSet<>();
-        String[] descSegments = unsupportedAbiDescription.split(":");
-        if (descSegments.length == 2) {
-            for (String abi : descSegments[1].split(",")) {
-                String trimmedAbi = abi.trim();
-                if (isAbiSupportedByCts(trimmedAbi)) {
-                    abiSet.add(trimmedAbi);
-                }
-            }
-        }
-        return abiSet;
-    }
-}
diff --git a/libs/commonutil/src/com/android/cts/util/MeasureRun.java b/libs/commonutil/src/com/android/cts/util/MeasureRun.java
deleted file mode 100644
index 43b5acf..0000000
--- a/libs/commonutil/src/com/android/cts/util/MeasureRun.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.util;
-
-/**
- * interface for measuring time for each run.
- */
-public abstract class MeasureRun {
-    /**
-     *  called before each run. not included to time measurement.
-     */
-    public void prepare(int i) throws Exception {
-        // default empty implementation
-    };
-
-    abstract public void run(int i) throws Exception;
-}
diff --git a/libs/commonutil/src/com/android/cts/util/MeasureTime.java b/libs/commonutil/src/com/android/cts/util/MeasureTime.java
deleted file mode 100644
index fd22ef2..0000000
--- a/libs/commonutil/src/com/android/cts/util/MeasureTime.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.util;
-
-
-public class MeasureTime {
-    /**
-     * measure time taken for each run for given count
-     * @param count
-     * @param run
-     * @return array of time taken in each run in msec.
-     * @throws Exception
-     */
-    public static double[] measure(int count, MeasureRun run) throws Exception {
-        double[] result = new double[count];
-
-        for (int i = 0; i < count; i++) {
-            run.prepare(i);
-            long start = System.currentTimeMillis();
-            run.run(i);
-            long end =  System.currentTimeMillis();
-            result[i] = end - start;
-        }
-        return result;
-    }
-}
diff --git a/libs/commonutil/src/com/android/cts/util/ReportLog.java b/libs/commonutil/src/com/android/cts/util/ReportLog.java
index dd4b414..05dec0f 100644
--- a/libs/commonutil/src/com/android/cts/util/ReportLog.java
+++ b/libs/commonutil/src/com/android/cts/util/ReportLog.java
@@ -16,29 +16,28 @@
 
 package com.android.cts.util;
 
-import java.util.LinkedList;
-import java.util.List;
+import com.android.compatibility.common.util.Stat;
 
-import junit.framework.Assert;
+import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.IOException;
 
 /**
  * Utility class to print performance measurement result back to host.
  * For now, throws know exception with message.
  *
- * Format:
- * Message = summary log SUMMARY_SEPARATOR [LOG_SEPARATOR log]*
- * summary = message|target|unit|type|value, target can be " " if there is no target set.
- * log for array = classMethodName:line_number|message|unit|type|space seSummaryparated values
+ * This class is deprecated, use {@link com.android.compatibility.common.util.ReportLog}
+ * instead.
  */
+@Deprecated
 public class ReportLog {
-    private static final String LOG_SEPARATOR = "+++";
-    private static final String SUMMARY_SEPARATOR = "++++";
-    private static final String LOG_ELEM_SEPARATOR = "|";
 
-    private List<String> mMessages = new LinkedList<String> ();
-    private String mSummary = null;
     protected static int mDepth = 3;
+    protected com.android.compatibility.common.util.ReportLog mReportLog;
+
+    public ReportLog(com.android.compatibility.common.util.ReportLog reportLog) {
+        mReportLog = reportLog;
+    }
 
     /**
      * print array of values to output log
@@ -80,23 +79,11 @@
 
     private void doPrintArray(String testId, String message,
             double[] values, ResultType type, ResultUnit unit) {
-        StringBuilder builder = new StringBuilder();
-        // note mDepth + 1 as this function will be called by printVaue or printArray
-        // and we need caller of printValue / printArray
-        builder.append(testId);
-        builder.append(LOG_ELEM_SEPARATOR);
-        builder.append(message);
-        builder.append(LOG_ELEM_SEPARATOR);
-        builder.append(type.getXmlString());
-        builder.append(LOG_ELEM_SEPARATOR);
-        builder.append(unit.getXmlString());
-        builder.append(LOG_ELEM_SEPARATOR);
-        for (double v : values) {
-            builder.append(v);
-            builder.append(" ");
-        }
-        mMessages.add(builder.toString());
-        printLog(builder.toString());
+        mReportLog.addValues(testId, message, values,
+                com.android.compatibility.common.util.ResultType.parseReportString(
+                        type.getXmlString()),
+                com.android.compatibility.common.util.ResultUnit.parseReportString(
+                        unit.getXmlString()));
     }
 
     /**
@@ -113,18 +100,12 @@
      */
     public void printSummaryWithTarget(String message, double target, double value,
             ResultType type, ResultUnit unit) {
-        mSummary = message + LOG_ELEM_SEPARATOR + target + LOG_ELEM_SEPARATOR + type.getXmlString()
-                + LOG_ELEM_SEPARATOR + unit.getXmlString() + LOG_ELEM_SEPARATOR + value;
-        boolean resultOk = true;
-        if (type == ResultType.HIGHER_BETTER) {
-            resultOk = value >= target;
-        } else if (type == ResultType.LOWER_BETTER) {
-            resultOk = value <= target;
-        }
-        if (!resultOk) {
-            Assert.fail("Measured result " + value + " does not meet perf target " + target +
-                    " with type " + type.getXmlString());
-        }
+        // Ignore target
+        mReportLog.setSummary(message, value,
+                com.android.compatibility.common.util.ResultType.parseReportString(
+                        type.getXmlString()),
+                com.android.compatibility.common.util.ResultUnit.parseReportString(
+                        unit.getXmlString()));
     }
 
     /**
@@ -136,32 +117,24 @@
      * @param unit unit of the data
      */
     public void printSummary(String message, double value, ResultType type, ResultUnit unit) {
-        mSummary = message + LOG_ELEM_SEPARATOR + " " + LOG_ELEM_SEPARATOR + type.getXmlString() +
-                LOG_ELEM_SEPARATOR + unit.getXmlString() + LOG_ELEM_SEPARATOR + value;
+        mReportLog.setSummary(message, value,
+                com.android.compatibility.common.util.ResultType.parseReportString(
+                        type.getXmlString()),
+                com.android.compatibility.common.util.ResultUnit.parseReportString(
+                        unit.getXmlString()));
     }
 
     /**
      * @return a string representation of this report.
      */
     protected String generateReport() {
-        if ((mSummary == null) && mMessages.isEmpty()) {
-            // just return empty string
-            return "";
+        try {
+            return com.android.compatibility.common.util.ReportLog.serialize(mReportLog);
+        } catch (IllegalArgumentException | IllegalStateException | XmlPullParserException
+                | IOException e) {
+            e.printStackTrace();
         }
-        StringBuilder builder = new StringBuilder();
-        builder.append(mSummary);
-        builder.append(SUMMARY_SEPARATOR);
-        for (String entry : mMessages) {
-            builder.append(entry);
-            builder.append(LOG_SEPARATOR);
-        }
-        // delete the last separator
-        if (builder.length() >= LOG_SEPARATOR.length()) {
-            builder.delete(builder.length() - LOG_SEPARATOR.length(), builder.length());
-        }
-        mSummary = null;
-        mMessages.clear();
-        return builder.toString();
+        return null;
     }
 
     /**
@@ -172,27 +145,14 @@
      * @return
      */
     public static double calcRatePerSec(double change, double timeInMSec) {
-        if (timeInMSec == 0) {
-            return change * 1000.0 / 0.001; // do not allow zero
-        } else {
-            return change * 1000.0 / timeInMSec;
-        }
+        return Stat.calcRatePerSec(change, timeInMSec);
     }
 
     /**
      * array version of calcRatePerSecArray
      */
     public static double[] calcRatePerSecArray(double change, double[] timeInMSec) {
-        double[] result = new double[timeInMSec.length];
-        change *= 1000.0;
-        for (int i = 0; i < timeInMSec.length; i++) {
-            if (timeInMSec[i] == 0) {
-                result[i] = change / 0.001;
-            } else {
-                result[i] = change / timeInMSec[i];
-            }
-        }
-        return result;
+        return Stat.calcRatePerSecArray(change, timeInMSec);
     }
 
     /**
@@ -219,10 +179,4 @@
         return names;
     }
 
-    /**
-     * to be overridden by child to print message to be passed
-     */
-    protected void printLog(String msg) {
-
-    }
 }
diff --git a/libs/commonutil/src/com/android/cts/util/ResultType.java b/libs/commonutil/src/com/android/cts/util/ResultType.java
index a5a388c..dbe8602 100644
--- a/libs/commonutil/src/com/android/cts/util/ResultType.java
+++ b/libs/commonutil/src/com/android/cts/util/ResultType.java
@@ -18,7 +18,11 @@
 
 /**
  * Enum for distinguishing performance results.
+ *
+ * This class is deprecated, use {@link com.android.compatibility.common.util.ResultType}
+ * instead.
  */
+@Deprecated
 public enum ResultType {
     /** lower score shows better performance */
     LOWER_BETTER,
diff --git a/libs/commonutil/src/com/android/cts/util/ResultUnit.java b/libs/commonutil/src/com/android/cts/util/ResultUnit.java
index a216a7e..2148821 100644
--- a/libs/commonutil/src/com/android/cts/util/ResultUnit.java
+++ b/libs/commonutil/src/com/android/cts/util/ResultUnit.java
@@ -19,7 +19,10 @@
 /**
  * Enum for representing the unit of performance results.
  *
+ * This class is deprecated, use {@link com.android.compatibility.common.util.ResultUnit}
+ * instead.
  */
+@Deprecated
 public enum ResultUnit {
     /** for value with no unit */
     NONE,
diff --git a/libs/commonutil/src/com/android/cts/util/Stat.java b/libs/commonutil/src/com/android/cts/util/Stat.java
deleted file mode 100644
index ceafa4e..0000000
--- a/libs/commonutil/src/com/android/cts/util/Stat.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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.util;
-
-import java.util.Arrays;
-
-/**
- * Utilities for doing statistics
- *
- */
-public class Stat {
-
-    /**
-     * Collection of statistical propertirs like average, max, min, and stddev
-     */
-    public static class StatResult {
-        public double mAverage;
-        public double mMin;
-        public double mMax;
-        public double mStddev;
-        public int mDataCount;
-        public StatResult(double average, double min, double max, double stddev, int dataCount) {
-            mAverage = average;
-            mMin = min;
-            mMax = max;
-            mStddev = stddev;
-            mDataCount = dataCount;
-        }
-    }
-
-    /**
-     * Calculate statistics properties likes average, min, max, and stddev for the given array
-     */
-    public static StatResult getStat(double[] data) {
-        double average = data[0];
-        double min = data[0];
-        double max = data[0];
-        double eX2 = data[0] * data[0]; // will become E[X^2]
-        for (int i = 1; i < data.length; i++) {
-            average += data[i];
-            eX2 += data[i] * data[i];
-            if (data[i] > max) {
-                max = data[i];
-            }
-            if (data[i] < min) {
-                min = data[i];
-            }
-        }
-        average /= data.length;
-        eX2 /= data.length;
-        // stddev = sqrt(E[X^2] - (E[X])^2)
-        double stddev = Math.sqrt(eX2 - average * average);
-        return new StatResult(average, min, max, stddev, data.length);
-    }
-
-    /**
-     * Calculate statistics properties likes average, min, max, and stddev for the given array
-     * while rejecting outlier +/- median * rejectionThreshold.
-     * rejectionThreshold should be bigger than 0.0 and be lowerthan 1.0
-     */
-    public static StatResult getStatWithOutlierRejection(double[] data, double rejectionThreshold) {
-        double[] dataCopied = Arrays.copyOf(data, data.length);
-        Arrays.sort(dataCopied);
-        int medianIndex = dataCopied.length / 2;
-        double median;
-        if (dataCopied.length % 2 == 1) {
-            median = dataCopied[medianIndex];
-        } else {
-            median = (dataCopied[medianIndex - 1] + dataCopied[medianIndex]) / 2.0;
-        }
-        double thresholdMin = median * (1.0 - rejectionThreshold);
-        double thresholdMax = median * (1.0 + rejectionThreshold);
-
-        double average = 0.0;
-        double min = median;
-        double max = median;
-        double eX2 = 0.0; // will become E[X^2]
-        int validDataCounter = 0;
-        for (int i = 0; i < data.length; i++) {
-            if ((data[i] > thresholdMin) && (data[i] < thresholdMax)) {
-                validDataCounter++;
-                average += data[i];
-                eX2 += data[i] * data[i];
-                if (data[i] > max) {
-                    max = data[i];
-                }
-                if (data[i] < min) {
-                    min = data[i];
-                }
-            }
-            //TODO report rejected data
-        }
-        double stddev;
-        if (validDataCounter > 0) {
-            average /= validDataCounter;
-            eX2 /= validDataCounter;
-            // stddev = sqrt(E[X^2] - (E[X])^2)
-            stddev = Math.sqrt(eX2 - average * average);
-        } else { // both median is showing too much diff
-            average = median;
-            stddev = 0; // don't care
-        }
-
-        return new StatResult(average, min, max, stddev, validDataCounter);
-    }
-
-    /**
-     * return the average value of the passed array
-     */
-    public static double getAverage(double[] data) {
-        double sum = data[0];
-        for (int i = 1; i < data.length; i++) {
-            sum += data[i];
-        }
-        return sum / data.length;
-    }
-
-    /**
-     * return the minimum value of the passed array
-     */
-    public static double getMin(double[] data) {
-        double min = data[0];
-        for (int i = 1; i < data.length; i++) {
-            if (data[i] < min) {
-                min = data[i];
-            }
-        }
-        return min;
-    }
-
-    /**
-     * return the maximum value of the passed array
-     */
-    public static double getMax(double[] data) {
-        double max = data[0];
-        for (int i = 1; i < data.length; i++) {
-            if (data[i] > max) {
-                max = data[i];
-            }
-        }
-        return max;
-    }
-}
diff --git a/libs/commonutil/src/com/android/cts/util/StatisticsUtils.java b/libs/commonutil/src/com/android/cts/util/StatisticsUtils.java
deleted file mode 100644
index d6589af..0000000
--- a/libs/commonutil/src/com/android/cts/util/StatisticsUtils.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.util;
-
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Set of static helper methods for CTS tests.
- */
-public class StatisticsUtils {
-
-
-    /**
-     * Private constructor for static class.
-     */
-    private StatisticsUtils() {}
-
-    /**
-     * Get the value of the 95th percentile using nearest rank algorithm.
-     *
-     * @throws IllegalArgumentException if the collection is null or empty
-     */
-    public static <TValue extends Comparable<? super TValue>> TValue get95PercentileValue(
-            Collection<TValue> collection) {
-        validateCollection(collection);
-
-        List<TValue> arrayCopy = new ArrayList<TValue>(collection);
-        Collections.sort(arrayCopy);
-
-        // zero-based array index
-        int arrayIndex = (int) Math.round(arrayCopy.size() * 0.95 + .5) - 1;
-
-        return arrayCopy.get(arrayIndex);
-    }
-
-    /**
-     * Calculate the mean of a collection.
-     *
-     * @throws IllegalArgumentException if the collection is null or empty
-     */
-    public static <TValue extends Number> double getMean(Collection<TValue> collection) {
-        validateCollection(collection);
-
-        double sum = 0.0;
-        for(TValue value : collection) {
-            sum += value.doubleValue();
-        }
-        return sum / collection.size();
-    }
-
-    /**
-     * Calculate the bias-corrected sample variance of a collection.
-     *
-     * @throws IllegalArgumentException if the collection is null or empty
-     */
-    public static <TValue extends Number> double getVariance(Collection<TValue> collection) {
-        validateCollection(collection);
-
-        double mean = getMean(collection);
-        ArrayList<Double> squaredDiffs = new ArrayList<Double>();
-        for(TValue value : collection) {
-            double difference = mean - value.doubleValue();
-            squaredDiffs.add(Math.pow(difference, 2));
-        }
-
-        double sum = 0.0;
-        for (Double value : squaredDiffs) {
-            sum += value;
-        }
-        return sum / (squaredDiffs.size() - 1);
-    }
-
-    /**
-     * Calculate the bias-corrected standard deviation of a collection.
-     *
-     * @throws IllegalArgumentException if the collection is null or empty
-     */
-    public static <TValue extends Number> double getStandardDeviation(
-            Collection<TValue> collection) {
-        return Math.sqrt(getVariance(collection));
-    }
-
-    /**
-     * Validate that a collection is not null or empty.
-     *
-     * @throws IllegalStateException if collection is null or empty.
-     */
-    private static <T> void validateCollection(Collection<T> collection) {
-        if(collection == null || collection.size() == 0) {
-            throw new IllegalStateException("Collection cannot be null or empty");
-        }
-    }
-
-}
diff --git a/libs/commonutil/src/com/android/cts/util/StatisticsUtilsTest.java b/libs/commonutil/src/com/android/cts/util/StatisticsUtilsTest.java
deleted file mode 100644
index d78ba99..0000000
--- a/libs/commonutil/src/com/android/cts/util/StatisticsUtilsTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.util;
-
-import junit.framework.TestCase;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Unit tests for the {@link StatisticsUtils} class.
- */
-public class StatisticsUtilsTest extends TestCase {
-
-    /**
-     * Test {@link StatisticsUtils#get95PercentileValue(Collection)}.
-     */
-    public void testGet95PercentileValue() {
-        Collection<Integer> values = new HashSet<Integer>();
-        for (int i = 0; i < 100; i++) {
-            values.add(i);
-        }
-        assertEquals(95, (int) StatisticsUtils.get95PercentileValue(values));
-
-        values = new HashSet<Integer>();
-        for (int i = 0; i < 1000; i++) {
-            values.add(i);
-        }
-        assertEquals(950, (int) StatisticsUtils.get95PercentileValue(values));
-
-        values = new HashSet<Integer>();
-        for (int i = 0; i < 100; i++) {
-            values.add(i * i);
-        }
-        assertEquals(95 * 95, (int) StatisticsUtils.get95PercentileValue(values));
-    }
-
-    /**
-     * Test {@link StatisticsUtils#getMean(Collection)}.
-     */
-    public void testGetMean() {
-        List<Integer> values = Arrays.asList(0, 1, 2, 3, 4);
-        double mean = StatisticsUtils.getMean(values);
-        assertEquals(2.0, mean, 0.00001);
-
-        values = Arrays.asList(1, 2, 3, 4, 5);
-        mean = StatisticsUtils.getMean(values);
-        assertEquals(3.0, mean, 0.00001);
-
-        values = Arrays.asList(0, 1, 4, 9, 16);
-        mean = StatisticsUtils.getMean(values);
-        assertEquals(6.0, mean, 0.00001);
-    }
-
-    /**
-     * Test {@link StatisticsUtils#getVariance(Collection)}.
-     */
-    public void testGetVariance() {
-        List<Integer> values = Arrays.asList(0, 1, 2, 3, 4);
-        double variance = StatisticsUtils.getVariance(values);
-        assertEquals(2.5, variance, 0.00001);
-
-        values = Arrays.asList(1, 2, 3, 4, 5);
-        variance = StatisticsUtils.getVariance(values);
-        assertEquals(2.5, variance, 0.00001);
-
-        values = Arrays.asList(0, 2, 4, 6, 8);
-        variance = StatisticsUtils.getVariance(values);
-        assertEquals(10.0, variance, 0.00001);
-    }
-
-    /**
-     * Test {@link StatisticsUtils#getStandardDeviation(Collection)}.
-     */
-    public void testGetStandardDeviation() {
-        List<Integer> values = Arrays.asList(0, 1, 2, 3, 4);
-        double stddev = StatisticsUtils.getStandardDeviation(values);
-        assertEquals(Math.sqrt(2.5), stddev, 0.00001);
-
-        values = Arrays.asList(1, 2, 3, 4, 5);
-        stddev = StatisticsUtils.getStandardDeviation(values);
-        assertEquals(Math.sqrt(2.5), stddev, 0.00001);
-
-        values = Arrays.asList(0, 2, 4, 6, 8);
-        stddev = StatisticsUtils.getStandardDeviation(values);
-        assertEquals(Math.sqrt(10.0), stddev, 0.00001);
-    }
-
-
-}
diff --git a/libs/deviceutil/Android.mk b/libs/deviceutil/Android.mk
index 8c81ee4..bb039ca 100644
--- a/libs/deviceutil/Android.mk
+++ b/libs/deviceutil/Android.mk
@@ -22,6 +22,8 @@
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util
+
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE := ctsdeviceutil
diff --git a/libs/deviceutil/src/android/cts/util/CtsActivityInstrumentationTestCase2.java b/libs/deviceutil/src/android/cts/util/CtsActivityInstrumentationTestCase2.java
deleted file mode 100644
index e039407..0000000
--- a/libs/deviceutil/src/android/cts/util/CtsActivityInstrumentationTestCase2.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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 android.cts.util;
-
-import com.android.cts.util.ReportLog;
-
-import android.app.Activity;
-import android.test.ActivityInstrumentationTestCase2;
-
-
-public class CtsActivityInstrumentationTestCase2<T extends Activity> extends
-        ActivityInstrumentationTestCase2<T> {
-
-    private DeviceReportLog mReportLog = new DeviceReportLog();
-
-    public CtsActivityInstrumentationTestCase2(Class<T> activityClass) {
-        super(activityClass);
-    }
-
-    public ReportLog getReportLog() {
-        return mReportLog;
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mReportLog.deliverReportToHost(getInstrumentation());
-        super.tearDown();
-    }
-
-}
diff --git a/libs/deviceutil/src/android/cts/util/CtsAndroidTestCase.java b/libs/deviceutil/src/android/cts/util/CtsAndroidTestCase.java
index b1164bc..7cf0f7e 100644
--- a/libs/deviceutil/src/android/cts/util/CtsAndroidTestCase.java
+++ b/libs/deviceutil/src/android/cts/util/CtsAndroidTestCase.java
@@ -18,13 +18,14 @@
 package android.cts.util;
 
 import android.content.Context;
+import android.test.ActivityInstrumentationTestCase2;
 
 /**
  *  This class emulates AndroidTestCase, but internally it is ActivityInstrumentationTestCase2
  *  to access Instrumentation.
  *  DummyActivity is not supposed to be accessed.
  */
-public class CtsAndroidTestCase extends CtsActivityInstrumentationTestCase2<DummyActivity> {
+public class CtsAndroidTestCase extends ActivityInstrumentationTestCase2<DummyActivity> {
     public CtsAndroidTestCase() {
         super(DummyActivity.class);
     }
diff --git a/libs/deviceutil/src/android/cts/util/DeviceReportLog.java b/libs/deviceutil/src/android/cts/util/DeviceReportLog.java
index 63b07b7..4dd185e 100644
--- a/libs/deviceutil/src/android/cts/util/DeviceReportLog.java
+++ b/libs/deviceutil/src/android/cts/util/DeviceReportLog.java
@@ -22,6 +22,11 @@
 
 import com.android.cts.util.ReportLog;
 
+/**
+ * This class is deprecated, use {@link com.android.compatibility.common.util.DeviceReportLog}
+ * instead.
+ */
+@Deprecated
 public class DeviceReportLog extends ReportLog {
     private static final String TAG = "DeviceCtsReport";
     private static final String CTS_RESULT_KEY = "CTS_TEST_RESULT";
@@ -33,21 +38,17 @@
     }
 
     public DeviceReportLog(int depth) {
+        super(new com.android.compatibility.common.util.DeviceReportLog());
         mDepth = BASE_DEPTH + depth;
     }
 
-    @Override
-    protected void printLog(String msg) {
-        Log.i(TAG, msg);
-    }
-
     public void deliverReportToHost(Instrumentation instrumentation) {
         Log.i(TAG, "deliverReportToHost");
         String report = generateReport();
-        if (!report.equals("")) {
+        if (report != null && !report.isEmpty()) {
             Bundle output = new Bundle();
             output.putString(CTS_RESULT_KEY, report);
             instrumentation.sendStatus(INST_STATUS_IN_PROGRESS, output);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/libs/migration/Android.mk b/libs/migration/Android.mk
new file mode 100644
index 0000000..18dc837
--- /dev/null
+++ b/libs/migration/Android.mk
@@ -0,0 +1,32 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := tradefed-prebuilt
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := cts-migration-lib
+
+LOCAL_SDK_VERSION := current
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/libs/migration/src/com/android/cts/migration/MigrationHelper.java b/libs/migration/src/com/android/cts/migration/MigrationHelper.java
new file mode 100644
index 0000000..5fa0ff8
--- /dev/null
+++ b/libs/migration/src/com/android/cts/migration/MigrationHelper.java
@@ -0,0 +1,53 @@
+package com.android.cts.migration;
+
+import com.android.tradefed.build.IBuildInfo;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * A temporary helper to enable tests to work with both cts v1 and v2.
+ */
+public class MigrationHelper {
+
+    private static final String COMPATIBILITY_BUILD_HELPER =
+            "com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper";
+    private static final String CTS_BUILD_HELPER =
+            "com.android.cts.tradefed.build.CtsBuildHelper";
+
+    public static File getTestFile(IBuildInfo mBuild, String filename)
+            throws FileNotFoundException {
+        try {
+            Class<?> cls = Class.forName(COMPATIBILITY_BUILD_HELPER);
+            Constructor<?> cons = cls.getConstructor(IBuildInfo.class);
+            Object instance = cons.newInstance(mBuild);
+            Method method = cls.getMethod("getTestsDir");
+            File dir = (File) method.invoke(instance);
+            File file = new File(dir, filename);
+            if (file.exists()) {
+                return file;
+            }
+        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
+                IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+            // Ignore and fall back to CtsBuildHelper
+        }
+        try {
+            Class<?> cls = Class.forName(CTS_BUILD_HELPER);
+            Method builder = cls.getMethod("createBuildHelper", IBuildInfo.class);
+            Object helper = builder.invoke(null, mBuild);
+            Method method = cls.getMethod("getTestApp", String.class);
+            File file = (File) method.invoke(helper, filename);
+            if (file.exists()) {
+                return file;
+            }
+        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
+                IllegalArgumentException | InvocationTargetException e) {
+            // Ignore
+        }
+        throw new FileNotFoundException("Couldn't load file " + filename);
+    }
+
+}
diff --git a/libs/vogar-expect/src/vogar/ExpectationStore.java b/libs/vogar-expect/src/vogar/ExpectationStore.java
index 090322d..b7b8d5a 100644
--- a/libs/vogar-expect/src/vogar/ExpectationStore.java
+++ b/libs/vogar-expect/src/vogar/ExpectationStore.java
@@ -27,12 +27,14 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
+
 import vogar.commands.Command;
 import vogar.util.Log;
 
@@ -269,4 +271,12 @@
             }
         }
     }
+
+    public Map<String, Expectation> getAllOutComes() {
+        return outcomes;
+    }
+
+    public Map<String, Expectation> getAllFailures() {
+        return failures;
+    }
 }
diff --git a/run_unit_tests.sh b/run_unit_tests.sh
new file mode 100755
index 0000000..d83da77
--- /dev/null
+++ b/run_unit_tests.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+# Copyright (C) 2015 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.
+
+# Helper script for running unit tests for compatibility libraries
+
+CTS_DIR=$(dirname ${0})
+source ${CTS_DIR}/test_defs.sh
+
+echo
+echo "---- BUILD ---- "
+echo
+
+# check if in Android build env
+if [ ! -z ${ANDROID_BUILD_TOP} ]; then
+    HOST=`uname`
+    if [ "$HOST" == "Linux" ]; then
+        OS="linux-x86"
+    elif [ "$HOST" == "Darwin" ]; then
+        OS="darwin-x86"
+    else
+        echo "Unrecognized OS"
+        exit
+    fi;
+fi;
+
+BUILD_TARGETS="
+    compatibility-common-util-tests\
+    compatibility-host-util-tests\
+    compatibility-device-util-tests\
+    compatibility-tradefed-tests\
+    cts-tradefed-tests_v2\
+    compatibility-device-info-tests\
+    compatibility-manifest-generator-tests
+    compatibility-host-media-preconditions-tests\
+    CompatibilityTestApp"
+
+pushd ${CTS_DIR}/..
+make ${BUILD_TARGETS} -j32
+BUILD_STATUS=$?
+popd
+if [ "${BUILD_STATUS}" != "0" ]; then
+    echo "BUILD FAILED - EXIT"
+    exit 1;
+fi;
+
+
+echo
+echo "---- DEVICE-SIDE TESTS ---- "
+echo
+
+${CTS_DIR}/common/device-side/test-app/run_tests.sh
+
+echo
+echo "---- HOST TESTS ---- "
+echo
+
+############### Run the host side tests ###############
+${CTS_DIR}/common/host-side/tradefed/tests/run_tests.sh
+${CTS_DIR}/common/host-side/manifest-generator/tests/run_tests.sh
+${CTS_DIR}/common/host-side/util/tests/run_tests.sh
+${CTS_DIR}/common/util/tests/run_tests.sh
+
+${CTS_DIR}/tools/cts-tradefed/tests/run_tests.sh
+
+${CTS_DIR}/tests/tests/mediastress/preconditions/tests/run_tests.sh
diff --git a/suite/cts/deviceTests/browserbench/Android.mk b/suite/cts/deviceTests/browserbench/Android.mk
deleted file mode 100644
index 3696bcd..0000000
--- a/suite/cts/deviceTests/browserbench/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ctstestserver
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceBrowserBench
-
-LOCAL_SDK_VERSION := 16
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/suite/cts/deviceTests/browserbench/AndroidManifest.xml b/suite/cts/deviceTests/browserbench/AndroidManifest.xml
deleted file mode 100644
index 4bf5b5e..0000000
--- a/suite/cts/deviceTests/browserbench/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.browser">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.browser" />
-</manifest>
diff --git a/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java b/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java
deleted file mode 100644
index d74ddb2..0000000
--- a/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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.browser;
-
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.cts.util.WatchDog;
-import android.net.Uri;
-import android.provider.Browser;
-import android.util.Log;
-import android.webkit.cts.CtsTestServer;
-
-import android.cts.util.CtsAndroidTestCase;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.cts.util.Stat;
-import com.android.cts.util.TimeoutReq;
-
-import java.net.URLDecoder;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
-import org.apache.http.RequestLine;
-/**
- * Browser benchmarking.
- * It launches an activity with URL and wait for POST from the client.
- */
-public class BrowserBenchTest extends CtsAndroidTestCase {
-    private static final String TAG = BrowserBenchTest.class.getSimpleName();
-    private static final boolean DEBUG = false;
-    private static final String OCTANE_START_FILE = "octane/index.html";
-    private static final String ROBOHORNET_START_FILE = "robohornet/robohornet.html";
-    private static final String HOST_COMPLETION_BROADCAST = "com.android.cts.browser.completion";
-    // time-out for watch-dog. POST should happen within this time.
-    private static long BROWSER_POST_TIMEOUT_IN_MS = 10 * 60 * 1000L;
-    // watch-dog will time-out first. So make it long enough.
-    private static long BROWSER_COMPLETION_TIMEOUT_IN_MS = 60 * 60 * 1000L;
-    private static final String HTTP_USER_AGENT = "User-Agent";
-    private CtsTestServer mWebServer;
-    // used for final score
-    private ResultType mTypeNonFinal = ResultType.NEUTRAL;
-    private ResultUnit mUnitNonFinal = ResultUnit.NONE;
-    // used for all other scores
-    private ResultType mTypeFinal = ResultType.NEUTRAL;
-    private ResultUnit mUnitFinal = ResultUnit.SCORE;
-    private WatchDog mWatchDog;
-    private CountDownLatch mLatch;
-    // can be changed by each test before starting
-    private volatile int mNumberRepeat;
-    /** tells how many tests have run up to now */
-    private volatile int mRunIndex;
-    /** stores results for each runs. last entry will be the final score. */
-    private LinkedHashMap<String, double[]> mResultsMap;
-    private PackageManager mPackageManager;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mPackageManager = getInstrumentation().getContext().getPackageManager();
-        mWebServer = new CtsTestServer(getContext()) {
-            @Override
-            protected HttpResponse onPost(HttpRequest request) throws Exception {
-                // post uri will look like "cts_report.html?final=1&score=10.1&message=hello"
-                RequestLine requestLine = request.getRequestLine();
-                String uriString = URLDecoder.decode(requestLine.getUri(), "UTF-8");
-                if (DEBUG) {
-                    Log.i(TAG, "uri:" + uriString);
-                }
-                String resultRe =
-                        ".*cts_report.html\\?final=([\\d])&score=([\\d]+\\.?[\\d]*)&message=([\\w][\\w ]*)";
-                Pattern resultPattern = Pattern.compile(resultRe);
-                Matcher matchResult = resultPattern.matcher(uriString);
-                if (matchResult.find()) {
-                    int isFinal = Integer.parseInt(matchResult.group(1));
-                    double score = Double.parseDouble(matchResult.group(2));
-                    String message = matchResult.group(3);
-                    Log.i(TAG, message + ":" + score);
-                    if (!mResultsMap.containsKey(message)) {
-                        mResultsMap.put(message, new double[mNumberRepeat]);
-                    }
-                    double[] scores = mResultsMap.get(message);
-                    scores[mRunIndex] = score;
-                    if (isFinal == 1) {
-                        String userAgent = request.getFirstHeader(HTTP_USER_AGENT).getValue();
-                        getReportLog().printValue(HTTP_USER_AGENT + "=" + userAgent, 0,
-                                ResultType.NEUTRAL, ResultUnit.NONE);
-                        mLatch.countDown();
-                    }
-                    mWatchDog.reset();
-                }
-                return null; // default response is OK as it will be ignored by client anyway.
-            }
-        };
-        mResultsMap = new LinkedHashMap<String, double[]>();
-        mWatchDog = new WatchDog(BROWSER_POST_TIMEOUT_IN_MS);
-        mWatchDog.start();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mWatchDog.stop();
-        mWebServer.shutdown();
-        mWebServer = null;
-        mResultsMap = null;
-        super.tearDown();
-    }
-
-    @TimeoutReq(minutes = 60)
-    public void testOctane() throws InterruptedException {
-        if (!isBrowserSupported()) {
-            Log.i(TAG, "Skipping test for device with no supported browser");
-            return;
-        }
-        String url = mWebServer.getAssetUrl(OCTANE_START_FILE) + "?auto=1";
-        final int kRepeat = 5;
-        doTest(url, ResultType.LOWER_BETTER, ResultUnit.MS,
-                ResultType.HIGHER_BETTER, ResultUnit.SCORE, kRepeat);
-    }
-
-    private void doTest(String url, ResultType typeNonFinal, ResultUnit unitNonFinal,
-            ResultType typeFinal, ResultUnit unitFinal, int numberRepeat)
-                    throws InterruptedException {
-        mTypeNonFinal = typeNonFinal;
-        mUnitNonFinal = unitNonFinal;
-        mTypeFinal = typeFinal;
-        mUnitFinal = unitFinal;
-        mNumberRepeat = numberRepeat;
-        Uri uri = Uri.parse(url);
-        for (mRunIndex = 0; mRunIndex < numberRepeat; mRunIndex++) {
-            Log.i(TAG, mRunIndex + "-th round");
-            mLatch = new CountDownLatch(1);
-            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            // force using only one window or tab
-            intent.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName());
-            getContext().startActivity(intent);
-            boolean ok = mLatch.await(BROWSER_COMPLETION_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS);
-            assertTrue("timed-out", ok);
-        }
-        // it is somewhat awkward to handle the last one specially with Map
-        int numberEntries = mResultsMap.size();
-        int numberToProcess = 1;
-        for (Map.Entry<String, double[]> entry : mResultsMap.entrySet()) {
-            String message = entry.getKey();
-            double[] scores = entry.getValue();
-            if (numberToProcess == numberEntries) { // final score
-                // store the whole results first
-                getReportLog().printArray(message, scores, mTypeFinal, mUnitFinal);
-                getReportLog().printSummary(message, Stat.getAverage(scores), mTypeFinal,
-                        mUnitFinal);
-            } else { // interim results
-                getReportLog().printArray(message, scores, mTypeNonFinal, mUnitNonFinal);
-            }
-            numberToProcess++;
-        }
-    }
-
-    /**
-     * @return true iff this device is has a working browser.
-     */
-    private boolean isBrowserSupported() {
-        return !(mPackageManager.hasSystemFeature("android.hardware.type.television")
-                 || mPackageManager.hasSystemFeature("android.software.leanback")
-                 || mPackageManager.hasSystemFeature("android.hardware.type.watch"));
-    }
-}
diff --git a/suite/cts/deviceTests/dram/Android.mk b/suite/cts/deviceTests/dram/Android.mk
deleted file mode 100644
index 879d151..0000000
--- a/suite/cts/deviceTests/dram/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
-
-LOCAL_JNI_SHARED_LIBRARIES := libctsdram_jni
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceDram
-
-LOCAL_SDK_VERSION := 16
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/suite/cts/deviceTests/dram/AndroidManifest.xml b/suite/cts/deviceTests/dram/AndroidManifest.xml
deleted file mode 100644
index c9aaf3d..0000000
--- a/suite/cts/deviceTests/dram/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.dram">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.dram"
-            android:label="DRAM bandwidth measurement" />
-</manifest>
diff --git a/suite/cts/deviceTests/dram/jni/MemoryNativeJni.cpp b/suite/cts/deviceTests/dram/jni/MemoryNativeJni.cpp
deleted file mode 100644
index 7d9a5fc..0000000
--- a/suite/cts/deviceTests/dram/jni/MemoryNativeJni.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.
- */
-
-#include <jni.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-
-double currentTimeMillis()
-{
-    struct timeval tv;
-    gettimeofday(&tv, (struct timezone *) NULL);
-    return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
-}
-
-extern "C" JNIEXPORT jdouble JNICALL Java_com_android_cts_dram_MemoryNative_runMemcpy(JNIEnv* env,
-        jclass clazz, jint bufferSize, jint repetition)
-{
-    char* src = new char[bufferSize];
-    char* dst = new char[bufferSize];
-    if ((src == NULL) || (dst == NULL)) {
-        delete[] src;
-        delete[] dst;
-        env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), "No memory");
-        return -1;
-    }
-    memset(src, 0, bufferSize);
-    memset(dst, 0, bufferSize);
-    double start = currentTimeMillis();
-    for (int i = 0; i < repetition; i++) {
-        memcpy(dst, src, bufferSize);
-        src[bufferSize - 1] = i & 0xff;
-    }
-    double end = currentTimeMillis();
-    delete[] src;
-    delete[] dst;
-    return end - start;
-}
-
-extern "C" JNIEXPORT jdouble JNICALL Java_com_android_cts_dram_MemoryNative_runMemset(JNIEnv* env,
-        jclass clazz, jint bufferSize, jint repetition, jint c)
-{
-    char* dst = new char[bufferSize];
-    if (dst == NULL) {
-        delete[] dst;
-        env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), "No memory");
-        return -1;
-    }
-    memset(dst, 0, bufferSize);
-    double start = currentTimeMillis();
-    for (int i = 0; i < repetition; i++) {
-        memset(dst, (c + i) & 0xff, bufferSize);
-    }
-    double end = currentTimeMillis();
-    delete[] dst;
-    return end - start;
-}
-
diff --git a/suite/cts/deviceTests/dram/src/com/android/cts/dram/BandwidthTest.java b/suite/cts/deviceTests/dram/src/com/android/cts/dram/BandwidthTest.java
deleted file mode 100644
index eeb7f9b..0000000
--- a/suite/cts/deviceTests/dram/src/com/android/cts/dram/BandwidthTest.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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.dram;
-
-import android.content.Context;
-import android.graphics.Point;
-import android.util.Log;
-import android.view.WindowManager;
-
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import android.cts.util.CtsAndroidTestCase;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.Stat;
-
-/**
- * check how many screens the memcpy function can copy in a sec.
- * Note that this does not represent the total memory bandwidth available in the system
- * as typically CPU cannot use the whole bandwidth.
- * Smaller buffers can fit into L1 or L2 cache, which can show big boost.
- */
-public class BandwidthTest extends CtsAndroidTestCase {
-    private static final String TAG = BandwidthTest.class.getSimpleName();
-    private static final int MEMCPY_REPETITION = 10;
-    private static final int MEMSET_REPETITION = 30;
-    private static final int REPEAT_IN_EACH_CALL = 100;
-    private static final int KB = 1024;
-    private static final int MB = 1024 * 1024;
-    private static final int MEMSET_CHAR = 0xa5;
-    // reject data outside +/- this value * median
-    private static final double OUTLIER_THRESHOLD = 0.1;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // warm-up
-        MemoryNative.runMemcpy(2 * MB, 100);
-    }
-
-    public void testMemcpyK004() {
-        doRunMemcpy(4 * KB);
-    }
-
-    public void testMemcpyK008() {
-        doRunMemcpy(8 * KB);
-    }
-
-    public void testMemcpyK016() {
-        doRunMemcpy(16 * KB);
-    }
-
-    public void testMemcpyK032() {
-        doRunMemcpy(32 * KB);
-    }
-
-    public void testMemcpyK064() {
-        doRunMemcpy(64 * KB);
-    }
-
-    public void testMemcpyK128() {
-        doRunMemcpy(128 * KB);
-    }
-
-    public void testMemcpyK256() {
-        doRunMemcpy(256 * KB);
-    }
-
-    public void testMemcpyK512() {
-        doRunMemcpy(512 * KB);
-    }
-
-    public void testMemcpyM001() {
-        doRunMemcpy(1 * MB);
-    }
-
-    public void testMemcpyM002() {
-        doRunMemcpy(2 * MB);
-    }
-
-    public void testMemcpyM004() {
-        doRunMemcpy(4 * MB);
-    }
-
-    public void testMemcpyM008() {
-        doRunMemcpy(8 * MB);
-    }
-
-    public void testMemcpyM016() {
-        doRunMemcpy(16 * MB);
-    }
-
-    public void testMemsetK004() {
-        doRunMemset(4 * KB);
-    }
-
-    public void testMemsetK008() {
-        doRunMemset(8 * KB);
-    }
-
-    public void testMemsetK016() {
-        doRunMemset(16 * KB);
-    }
-
-    public void testMemsetK032() {
-        doRunMemset(32 * KB);
-    }
-
-    public void testMemsetK064() {
-        doRunMemset(64 * KB);
-    }
-
-    public void testMemsetK128() {
-        doRunMemset(128 * KB);
-    }
-
-    public void testMemsetK256() {
-        doRunMemset(256 * KB);
-    }
-
-    public void testMemsetK512() {
-        doRunMemset(512 * KB);
-    }
-
-    public void testMemsetM001() {
-        doRunMemset(1 * MB);
-    }
-
-    public void testMemsetM002() {
-        doRunMemset(2 * MB);
-    }
-
-    public void testMemsetM004() {
-        doRunMemset(4 * MB);
-    }
-
-    public void testMemsetM008() {
-        doRunMemset(8 * MB);
-    }
-
-    public void testMemsetM016() {
-        doRunMemset(16 * MB);
-    }
-
-    private void doRunMemcpy(int bufferSize) {
-        double[] result = new double[MEMCPY_REPETITION];
-        int repeatInEachCall = REPEAT_IN_EACH_CALL;
-        if (bufferSize < (1 * MB)) {
-            // too small buffer size finishes too early to give accurate result.
-            repeatInEachCall *= (1 * MB / bufferSize);
-        }
-        for (int i = 0; i < MEMCPY_REPETITION; i++) {
-            result[i] = MemoryNative.runMemcpy(bufferSize, repeatInEachCall);
-        }
-        getReportLog().printArray("memcpy time", result, ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-        double[] mbps = ReportLog.calcRatePerSecArray(
-                (double)bufferSize * repeatInEachCall / 1024.0 / 1024.0, result);
-        getReportLog().printArray("memcpy throughput", mbps, ResultType.HIGHER_BETTER,
-                ResultUnit.MBPS);
-        Stat.StatResult stat = Stat.getStatWithOutlierRejection(mbps, OUTLIER_THRESHOLD);
-        if (stat.mDataCount != result.length) {
-            Log.w(TAG, "rejecting " + (result.length - stat.mDataCount) + " outliers");
-        }
-        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
-        Point size = new Point();
-        wm.getDefaultDisplay().getSize(size);
-        Log.i(TAG, " x " + size.x + " y " + size.y);
-        double pixels = size.x * size.y;
-        // now this represents how many times the whole screen can be copied in a sec.
-        double screensPerSecAverage = stat.mAverage / pixels * 1024.0 * 1024.0 / 4.0;
-        getReportLog().printValue("memcpy in fps", screensPerSecAverage,
-                ResultType.HIGHER_BETTER, ResultUnit.FPS);
-        getReportLog().printSummary("memcpy throughput", stat.mAverage, ResultType.HIGHER_BETTER,
-                ResultUnit.MBPS);
-    }
-
-    private void doRunMemset(int bufferSize) {
-        double[] result = new double[MEMSET_REPETITION];
-        int repeatInEachCall = REPEAT_IN_EACH_CALL;
-        if (bufferSize < (1 * MB)) {
-            // too small buffer size finishes too early to give accurate result.
-            repeatInEachCall *= (1 * MB / bufferSize);
-        }
-        for (int i = 0; i < MEMSET_REPETITION; i++) {
-            result[i] = MemoryNative.runMemset(bufferSize, repeatInEachCall, MEMSET_CHAR);
-        }
-        getReportLog().printArray("memset time", result, ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-        double[] mbps = ReportLog.calcRatePerSecArray(
-                (double)bufferSize * repeatInEachCall / 1024.0 / 1024.0, result);
-        getReportLog().printArray("memset throughput", mbps, ResultType.HIGHER_BETTER,
-                ResultUnit.MBPS);
-        Stat.StatResult stat = Stat.getStatWithOutlierRejection(mbps, OUTLIER_THRESHOLD);
-        if (stat.mDataCount != result.length) {
-            Log.w(TAG, "rejecting " + (result.length - stat.mDataCount) + " outliers");
-        }
-        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
-        Point size = new Point();
-        wm.getDefaultDisplay().getSize(size);
-        Log.i(TAG, " x " + size.x + " y " + size.y);
-        double pixels = size.x * size.y;
-        // now this represents how many times the whole screen can be copied in a sec.
-        double screensPerSecAverage = stat.mAverage / pixels * 1024.0 * 1024.0 / 4.0;
-        getReportLog().printValue("memset in fps", screensPerSecAverage,
-                ResultType.HIGHER_BETTER, ResultUnit.FPS);
-        getReportLog().printSummary("memset throughput", stat.mAverage, ResultType.HIGHER_BETTER,
-                ResultUnit.MBPS);
-    }
-}
diff --git a/suite/cts/deviceTests/dram/src/com/android/cts/dram/MemoryNative.java b/suite/cts/deviceTests/dram/src/com/android/cts/dram/MemoryNative.java
deleted file mode 100644
index e55127d..0000000
--- a/suite/cts/deviceTests/dram/src/com/android/cts/dram/MemoryNative.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.dram;
-
-public class MemoryNative {
-    static {
-        System.loadLibrary("ctsdram_jni");
-    }
-    /**
-     * run memcpy for given number of repetition from a source to a destination buffers
-     * with each having the size of bufferSize.
-     * @param bufferSize
-     * @param repeatition
-     * @return time spent in copying in ms.
-     */
-    public static native double runMemcpy(int bufferSize, int repetition);
-
-    /**
-     * run memset for given number of repetition from a source to a destination buffers
-     * with each having the size of bufferSize.
-     * @param bufferSize
-     * @param repetition
-     * @param c char to set. Only LSBs will be used to get char value.
-     * @return time spent in memset in ms.
-     */
-    public static native double runMemset(int bufferSize, int repetition, int c);
-}
diff --git a/suite/cts/deviceTests/filesystemperf/Android.mk b/suite/cts/deviceTests/filesystemperf/Android.mk
deleted file mode 100644
index 7ee93de..0000000
--- a/suite/cts/deviceTests/filesystemperf/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceFilePerf
-
-LOCAL_SDK_VERSION := 16
-
-cts_runtime_hint := 28
-
-include $(BUILD_CTS_PACKAGE)
-
diff --git a/suite/cts/deviceTests/filesystemperf/AndroidManifest.xml b/suite/cts/deviceTests/filesystemperf/AndroidManifest.xml
deleted file mode 100644
index 329bf19..0000000
--- a/suite/cts/deviceTests/filesystemperf/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.filesystemperf">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.filesystemperf"
-            android:label="UI Latency measurement" />
-</manifest>
diff --git a/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/AlmostFullTest.java b/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/AlmostFullTest.java
deleted file mode 100644
index ab81f16..0000000
--- a/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/AlmostFullTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.filesystemperf;
-
-import android.util.Log;
-
-import android.cts.util.CtsAndroidTestCase;
-import android.cts.util.SystemUtil;
-
-import com.android.cts.util.TimeoutReq;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class AlmostFullTest extends CtsAndroidTestCase {
-
-    private static final String DIR_INITIAL_FILL = "INITIAL_FILL";
-    private static final String DIR_SEQ_UPDATE = "SEQ_UPDATE";
-    private static final String DIR_RANDOM_WR = "RANDOM_WR";
-    private static final String DIR_RANDOM_RD = "RANDOM_RD";
-    private static final String TAG = "AlmostFullTest";
-
-    private static final long FREE_SPACE_FINAL = 1000L * 1024 * 1024L;
-
-    // test runner creates multiple instances at the begging.
-    // use that to fill disk only once.
-    // set as final to initialize it only once
-    private static final AtomicInteger mRefCounter = new AtomicInteger(0);
-    private static final AtomicBoolean mDiskFilled = new AtomicBoolean(false);
-
-    public AlmostFullTest() {
-        int currentCounter = mRefCounter.incrementAndGet();
-        Log.i(TAG, "++currentCounter: " + currentCounter);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        if (mDiskFilled.compareAndSet(false, true)) {
-            Log.i(TAG, "Filling disk");
-            // initial fill done in two stage as disk can be filled by other
-            // components
-            long freeDisk = SystemUtil.getFreeDiskSize(getContext());
-            long diskToFill = freeDisk - FREE_SPACE_FINAL;
-            if (diskToFill >= 0) {
-                Log.i(TAG, "free disk " + freeDisk + ", to fill " + diskToFill);
-            } else {
-                Log.i(TAG, "free disk " + freeDisk + " too small, needs " + FREE_SPACE_FINAL);
-                return;
-            }
-            final long MAX_FILE_SIZE_TO_FILL = 1024L * 1024L * 1024L;
-            long filled = 0;
-            while (filled < diskToFill) {
-                long toFill = diskToFill - filled;
-                if (toFill > MAX_FILE_SIZE_TO_FILL) {
-                    toFill = MAX_FILE_SIZE_TO_FILL;
-                }
-                Log.i(TAG, "Generating file " + toFill);
-                FileUtil.createNewFilledFile(getContext(),
-                        DIR_INITIAL_FILL, toFill);
-                filled += toFill;
-            }
-        }
-        Log.i(TAG, "free disk " + SystemUtil.getFreeDiskSize(getContext()));
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        Log.i(TAG, "tearDown free disk " + SystemUtil.getFreeDiskSize(getContext()));
-        int currentCounter = mRefCounter.decrementAndGet();
-        Log.i(TAG, "--currentCounter: " + currentCounter);
-        if (currentCounter == 0) {
-            FileUtil.removeFileOrDir(getContext(), DIR_INITIAL_FILL);
-        }
-        FileUtil.removeFileOrDir(getContext(), DIR_SEQ_UPDATE);
-        FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_WR);
-        FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_RD);
-        Log.i(TAG, "tearDown free disk " + SystemUtil.getFreeDiskSize(getContext()));
-        super.tearDown();
-    }
-
-    @TimeoutReq(minutes = 30)
-    public void testSequentialUpdate() throws Exception {
-        // now about freeSpaceToLeave should be left
-        // and try updating exceeding the free space size
-        final long FILE_SIZE = 400L * 1024L * 1024L;
-        long freeDisk = SystemUtil.getFreeDiskSize(getContext());
-        Log.i(TAG, "Now free space is " + freeDisk);
-        if (freeDisk < FILE_SIZE) {
-            Log.w(TAG, "too little space: " + freeDisk);
-            return;
-        }
-        final int BUFFER_SIZE = 10 * 1024 * 1024;
-        final int NUMBER_REPETITION = 10;
-        FileUtil.doSequentialUpdateTest(getContext(), DIR_SEQ_UPDATE, getReportLog(), FILE_SIZE,
-                BUFFER_SIZE, NUMBER_REPETITION);
-    }
-
-    // TODO: file size too small and caching will give wrong better result.
-    // needs to flush cache by reading big files per each read.
-    @TimeoutReq(minutes = 60)
-    public void testRandomRead() throws Exception {
-        final int BUFFER_SIZE = 4 * 1024;
-        final long fileSize = 400L * 1024L * 1024L;
-        long freeDisk = SystemUtil.getFreeDiskSize(getContext());
-        if (freeDisk < fileSize) {
-            Log.w(TAG, "too little space: " + freeDisk);
-            return;
-        }
-        FileUtil.doRandomReadTest(getContext(), DIR_RANDOM_RD, getReportLog(), fileSize,
-                BUFFER_SIZE);
-    }
-
-    @TimeoutReq(minutes = 60)
-    public void testRandomUpdate() throws Exception {
-        final int BUFFER_SIZE = 4 * 1024;
-        final long fileSize = 256L * 1024L * 1024L;
-        long freeDisk = SystemUtil.getFreeDiskSize(getContext());
-        if (freeDisk < fileSize) {
-            Log.w(TAG, "too little space: " + freeDisk);
-            return;
-        }
-        FileUtil.doRandomWriteTest(getContext(), DIR_RANDOM_WR, getReportLog(), fileSize,
-                BUFFER_SIZE);
-    }
-}
diff --git a/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/FileUtil.java b/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/FileUtil.java
deleted file mode 100755
index 6231774..0000000
--- a/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/FileUtil.java
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * 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.filesystemperf;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.RandomAccessFile;
-import java.util.Random;
-
-import com.android.cts.util.MeasureRun;
-import com.android.cts.util.MeasureTime;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.Stat;
-import android.cts.util.SystemUtil;
-
-import android.content.Context;
-import android.util.Log;
-
-public class FileUtil {
-    private static final String TAG = "FileUtil";
-    private static final Random mRandom = new Random(0);
-    private static long mFileId = 0;
-    /**
-     * create array with different data per each call
-     *
-     * @param length
-     * @param randomSeed
-     * @return
-     */
-    public static byte[] generateRandomData(int length) {
-        byte[] buffer = new byte[length];
-        int val = mRandom.nextInt();
-        for (int i = 0; i < length / 4; i++) {
-            // in little-endian
-            buffer[i * 4] = (byte)(val & 0x000000ff);
-            buffer[i * 4 + 1] = (byte)((val & 0x0000ff00) >> 8);
-            buffer[i * 4 + 2] = (byte)((val & 0x00ff0000) >> 16);
-            buffer[i * 4 + 3] = (byte)((val & 0xff000000) >> 24);
-            val++;
-        }
-        for (int i = (length / 4) * 4; i < length; i++) {
-            buffer[i] = 0;
-        }
-        return buffer;
-    }
-
-    /**
-     * create a new file under the given dirName.
-     * Existing files will not be affected.
-     * @param context
-     * @param dirName
-     * @return
-     */
-    public static File createNewFile(Context context, String dirName) {
-        File topDir = new File(context.getFilesDir(), dirName);
-        topDir.mkdir();
-        String[] list = topDir.list();
-
-        String newFileName;
-        while (true) {
-            newFileName = Long.toString(mFileId);
-            boolean fileExist = false;
-            for (String child : list) {
-                if (child.equals(newFileName)) {
-                    fileExist = true;
-                    break;
-                }
-            }
-            if (!fileExist) {
-                break;
-            }
-            mFileId++;
-        }
-        mFileId++;
-        //Log.i(TAG, "filename" + Long.toString(mFileId));
-        return new File(topDir, newFileName);
-    }
-
-    /**
-     * create multiple new files
-     * @param context
-     * @param dirName
-     * @param count number of files to create
-     * @return
-     */
-    public static File[] createNewFiles(Context context, String dirName, int count) {
-        File[] files = new File[count];
-        for (int i = 0; i < count; i++) {
-            files[i] = createNewFile(context, dirName);
-        }
-        return files;
-    }
-
-    /**
-     * write file with given byte array
-     * @param file
-     * @param data
-     * @param append will append if set true. Otherwise, write from beginning
-     * @throws IOException
-     */
-    public static void writeFile(File file, byte[] data, boolean append) throws IOException {
-        final RandomAccessFile randomFile = new RandomAccessFile(file, "rwd"); // force O_SYNC
-        if (append) {
-            randomFile.seek(randomFile.length());
-        } else {
-            randomFile.seek(0L);
-        }
-        randomFile.write(data);
-        randomFile.close();
-    }
-
-    /**
-     * create a new file with given length.
-     * @param context
-     * @param dirName
-     * @param length
-     * @return
-     * @throws IOException
-     */
-    public static File createNewFilledFile(Context context, String dirName, long length)
-            throws IOException {
-        final int BUFFER_SIZE = 10 * 1024 * 1024;
-        File file = createNewFile(context, dirName);
-        FileOutputStream out = new FileOutputStream(file);
-        byte[] data = generateRandomData(BUFFER_SIZE);
-        long written = 0;
-        while (written < length) {
-            out.write(data);
-            written += BUFFER_SIZE;
-        }
-        out.flush();
-        out.close();
-        return file;
-    }
-
-    /**
-     * remove given file or directory under the current app's files dir.
-     * @param context
-     * @param name
-     */
-    public static void removeFileOrDir(Context context, String name) {
-        File entry = new File(context.getFilesDir(), name);
-        if (entry.exists()) {
-            removeEntry(entry);
-        }
-    }
-
-    private static void removeEntry(File entry) {
-        if (entry.isDirectory()) {
-            String[] children = entry.list();
-            for (String child : children) {
-                removeEntry(new File(entry, child));
-            }
-        }
-        Log.i(TAG, "delete file " + entry.getAbsolutePath());
-        entry.delete();
-    }
-
-    /**
-     * measure time taken for each IO run with amount R/W
-     * @param count
-     * @param run
-     * @param readAmount returns amount of read in bytes for each interval.
-     *        Value will not be written if /proc/self/io does not exist.
-     * @param writeAmount returns amount of write in bytes for each interval.
-     * @return time per each interval
-     * @throws IOException
-     */
-    public static double[] measureIO(int count, double[] readAmount, double[] writeAmount,
-            MeasureRun run)  throws Exception {
-        double[] result = new double[count];
-        File procIo = new File("/proc/self/io");
-        boolean measureIo = procIo.exists() && procIo.canRead();
-        long prev = System.currentTimeMillis();
-        RWAmount prevAmount = new RWAmount();
-        if (measureIo) {
-            prevAmount = getRWAmount(procIo);
-        }
-        for (int i = 0; i < count; i++) {
-            run.run(i);
-            long current =  System.currentTimeMillis();
-            result[i] = current - prev;
-            prev = current;
-            if (measureIo) {
-                RWAmount currentAmount = getRWAmount(procIo);
-                readAmount[i] = currentAmount.mRd - prevAmount.mRd;
-                writeAmount[i] = currentAmount.mWr - prevAmount.mWr;
-                prevAmount = currentAmount;
-            }
-        }
-        return result;
-    }
-
-    private static class RWAmount {
-        public double mRd = 0.0;
-        public double mWr = 0.0;
-    };
-
-    private static RWAmount getRWAmount(File file) throws IOException {
-        RWAmount amount = new RWAmount();
-
-        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
-        String line;
-        while((line = br.readLine())!= null) {
-            if (line.startsWith("read_bytes")) {
-                amount.mRd = Double.parseDouble(line.split(" ")[1]);
-            } else if (line.startsWith("write_bytes")) {
-                amount.mWr = Double.parseDouble(line.split(" ")[1]);
-            }
-        }
-        br.close();
-        return amount;
-    }
-
-    /**
-     * get file size exceeding total memory size ( 2x total memory).
-     * The size is rounded in bufferSize. And the size will be bigger than 400MB.
-     * @param context
-     * @param bufferSize
-     * @return file size or 0 if there is not enough space.
-     */
-    public static long getFileSizeExceedingMemory(Context context, int bufferSize) {
-        long freeDisk = SystemUtil.getFreeDiskSize(context);
-        long memSize = SystemUtil.getTotalMemory(context);
-        long diskSizeTarget = (2 * memSize / bufferSize) * bufferSize;
-        final long minimumDiskSize = (512L * 1024L * 1024L / bufferSize) * bufferSize;
-        final long reservedDiskSize = (50L * 1024L * 1024L / bufferSize) * bufferSize;
-        if ( diskSizeTarget < minimumDiskSize ) {
-            diskSizeTarget = minimumDiskSize;
-        }
-        if (diskSizeTarget > freeDisk) {
-            Log.i(TAG, "Free disk size " + freeDisk + " too small");
-            return 0;
-        }
-        if ((freeDisk - diskSizeTarget) < reservedDiskSize) {
-            diskSizeTarget -= reservedDiskSize;
-        }
-        return diskSizeTarget;
-    }
-
-    /**
-     *
-     * @param context
-     * @param dirName
-     * @param report
-     * @param fileSize
-     * @param bufferSize should be power of two
-     * @throws IOException
-     */
-    public static void doRandomReadTest(Context context, String dirName, ReportLog report,
-            long fileSize, int bufferSize) throws Exception {
-        File file = FileUtil.createNewFilledFile(context,
-                dirName, fileSize);
-
-        final byte[] data = FileUtil.generateRandomData(bufferSize);
-        Random random = new Random(0);
-        final int totalReadCount = (int)(fileSize / bufferSize);
-        final int[] readOffsets = new int[totalReadCount];
-        for (int i = 0; i < totalReadCount; i++) {
-            // align in buffer size
-            readOffsets[i] = (int)(random.nextFloat() * (fileSize - bufferSize)) &
-                    ~(bufferSize - 1);
-        }
-        final int runsInOneGo = 16;
-        final int readsInOneMeasure = totalReadCount / runsInOneGo;
-
-        final RandomAccessFile randomFile = new RandomAccessFile(file, "rw"); // do not need O_SYNC
-        double[] rdAmount = new double[runsInOneGo];
-        double[] wrAmount = new double[runsInOneGo];
-        double[] times = FileUtil.measureIO(runsInOneGo, rdAmount, wrAmount, new MeasureRun() {
-
-            @Override
-            public void run(int i) throws IOException {
-                Log.i(TAG, "starting " + i + " -th round");
-                int start = i * readsInOneMeasure;
-                int end = (i + 1) * readsInOneMeasure;
-                for (int j = start; j < end; j++) {
-                    randomFile.seek(readOffsets[j]);
-                    randomFile.read(data);
-                }
-            }
-        });
-        randomFile.close();
-        double[] mbps = ReportLog.calcRatePerSecArray((double)fileSize / runsInOneGo / 1024 / 1024,
-                times);
-        report.printArray("read throughput",
-                mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
-        // This is just the amount of IO returned from kernel. So this is performance neutral.
-        report.printArray("read amount", rdAmount, ResultType.NEUTRAL, ResultUnit.BYTE);
-        Stat.StatResult stat = Stat.getStat(mbps);
-
-        report.printSummary("read throughput", stat.mAverage, ResultType.HIGHER_BETTER,
-                ResultUnit.MBPS);
-    }
-
-    /**
-     *
-     * @param context
-     * @param dirName
-     * @param report
-     * @param fileSize
-     * @param bufferSize should be power of two
-     * @throws IOException
-     */
-    public static void doRandomWriteTest(Context context, String dirName, ReportLog report,
-            long fileSize, int bufferSize) throws Exception {
-        File file = FileUtil.createNewFilledFile(context,
-                dirName, fileSize);
-        final byte[] data = FileUtil.generateRandomData(bufferSize);
-        Random random = new Random(0);
-        final int totalWriteCount = (int)(fileSize / bufferSize);
-        final int[] writeOffsets = new int[totalWriteCount];
-        for (int i = 0; i < totalWriteCount; i++) {
-            writeOffsets[i] = (int)(random.nextFloat() * (fileSize - bufferSize)) &
-                    ~(bufferSize - 1);
-        }
-        final int runsInOneGo = 16;
-        final int writesInOneMeasure = totalWriteCount / runsInOneGo;
-
-        final RandomAccessFile randomFile = new RandomAccessFile(file, "rwd"); // force O_SYNC
-        double[] rdAmount = new double[runsInOneGo];
-        double[] wrAmount = new double[runsInOneGo];
-        double[] times = FileUtil.measureIO(runsInOneGo, rdAmount, wrAmount, new MeasureRun() {
-
-            @Override
-            public void run(int i) throws IOException {
-                Log.i(TAG, "starting " + i + " -th round");
-                int start = i * writesInOneMeasure;
-                int end = (i + 1) * writesInOneMeasure;
-                for (int j = start; j < end; j++) {
-                    randomFile.seek(writeOffsets[j]);
-                    randomFile.write(data);
-                }
-            }
-        });
-        randomFile.close();
-        double[] mbps = ReportLog.calcRatePerSecArray((double)fileSize / runsInOneGo / 1024 / 1024,
-                times);
-        report.printArray("write throughput",
-                mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
-        report.printArray("write amount", wrAmount, ResultType.NEUTRAL,
-                ResultUnit.BYTE);
-        Stat.StatResult stat = Stat.getStat(mbps);
-
-        report.printSummary("write throughput", stat.mAverage, ResultType.HIGHER_BETTER,
-                ResultUnit.MBPS);
-    }
-
-    /**
-     *
-     * @param context
-     * @param dirName
-     * @param report
-     * @param fileSize fileSize should be multiple of bufferSize.
-     * @param bufferSize
-     * @param numberRepetition
-     * @throws IOException
-     */
-    public static void doSequentialUpdateTest(Context context, String dirName, ReportLog report,
-            long fileSize, int bufferSize, int numberRepetition) throws Exception {
-        File file = FileUtil.createNewFilledFile(context,
-                dirName, fileSize);
-        final byte[] data = FileUtil.generateRandomData(bufferSize);
-        int numberRepeatInOneRun = (int)(fileSize / bufferSize);
-        double[] mbpsAll = new double[numberRepetition * numberRepeatInOneRun];
-        for (int i = 0; i < numberRepetition; i++) {
-            Log.i(TAG, "starting " + i + " -th round");
-            final RandomAccessFile randomFile = new RandomAccessFile(file, "rwd");  // force O_SYNC
-            randomFile.seek(0L);
-            double[] times = MeasureTime.measure(numberRepeatInOneRun, new MeasureRun() {
-
-                @Override
-                public void run(int i) throws IOException {
-                    randomFile.write(data);
-                }
-            });
-            randomFile.close();
-            double[] mbps = ReportLog.calcRatePerSecArray((double)bufferSize / 1024 / 1024,
-                    times);
-            report.printArray(i + "-th round throughput",
-                    mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
-            ReportLog.copyArray(mbps, mbpsAll, i * numberRepeatInOneRun);
-        }
-        Stat.StatResult stat = Stat.getStat(mbpsAll);
-        report.printSummary("update throughput", stat.mAverage, ResultType.HIGHER_BETTER,
-                ResultUnit.MBPS);
-    }
-}
diff --git a/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/RandomRWTest.java b/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/RandomRWTest.java
deleted file mode 100644
index 6ad927b..0000000
--- a/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/RandomRWTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.filesystemperf;
-
-import android.cts.util.CtsAndroidTestCase;
-import com.android.cts.util.TimeoutReq;
-
-public class RandomRWTest extends CtsAndroidTestCase {
-    private static final String DIR_RANDOM_WR = "RANDOM_WR";
-    private static final String DIR_RANDOM_RD = "RANDOM_RD";
-
-    @Override
-    protected void tearDown() throws Exception {
-        FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_WR);
-        FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_RD);
-        super.tearDown();
-    }
-
-    @TimeoutReq(minutes = 60)
-    public void testRandomRead() throws Exception {
-        final int READ_BUFFER_SIZE = 4 * 1024;
-        final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), READ_BUFFER_SIZE);
-        if (fileSize == 0) { // not enough space, give up
-            return;
-        }
-        FileUtil.doRandomReadTest(getContext(), DIR_RANDOM_RD, getReportLog(), fileSize,
-                READ_BUFFER_SIZE);
-    }
-
-    // It is taking too long in some device, and thus cannot run multiple times
-    @TimeoutReq(minutes = 60)
-    public void testRandomUpdate() throws Exception {
-        final int WRITE_BUFFER_SIZE = 4 * 1024;
-        final long fileSize = 256 * 1024 * 1024;
-        FileUtil.doRandomWriteTest(getContext(), DIR_RANDOM_WR, getReportLog(), fileSize,
-                WRITE_BUFFER_SIZE);
-    }
-}
diff --git a/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/SequentialRWTest.java b/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/SequentialRWTest.java
deleted file mode 100644
index d369ce8..0000000
--- a/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/SequentialRWTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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.filesystemperf;
-
-import android.cts.util.CtsAndroidTestCase;
-import com.android.cts.util.MeasureRun;
-import com.android.cts.util.MeasureTime;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.Stat;
-import com.android.cts.util.TimeoutReq;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-
-public class SequentialRWTest extends CtsAndroidTestCase {
-    private static final String DIR_SEQ_WR = "SEQ_WR";
-    private static final String DIR_SEQ_UPDATE = "SEQ_UPDATE";
-    private static final String DIR_SEQ_RD = "SEQ_RD";
-    private static final int BUFFER_SIZE = 10 * 1024 * 1024;
-
-    @Override
-    protected void tearDown() throws Exception {
-        FileUtil.removeFileOrDir(getContext(), DIR_SEQ_WR);
-        FileUtil.removeFileOrDir(getContext(), DIR_SEQ_UPDATE);
-        FileUtil.removeFileOrDir(getContext(), DIR_SEQ_RD);
-        super.tearDown();
-    }
-
-    @TimeoutReq(minutes = 30)
-    public void testSingleSequentialWrite() throws Exception {
-        final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), BUFFER_SIZE);
-        if (fileSize == 0) { // not enough space, give up
-            return;
-        }
-        final int numberOfFiles =(int)(fileSize / BUFFER_SIZE);
-        getReportLog().printValue("files", numberOfFiles, ResultType.NEUTRAL,
-                ResultUnit.COUNT);
-        final byte[] data = FileUtil.generateRandomData(BUFFER_SIZE);
-        final File[] files = FileUtil.createNewFiles(getContext(), DIR_SEQ_WR,
-                numberOfFiles);
-        double[] rdAmount = new double[numberOfFiles];
-        double[] wrAmount = new double[numberOfFiles];
-        double[] times = FileUtil.measureIO(numberOfFiles, rdAmount, wrAmount, new MeasureRun() {
-
-            @Override
-            public void run(int i) throws IOException {
-                FileUtil.writeFile(files[i], data, false);
-            }
-        });
-        double[] mbps = ReportLog.calcRatePerSecArray((double)BUFFER_SIZE / 1024 / 1024, times);
-        getReportLog().printArray("write throughput",
-                mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
-        getReportLog().printArray("write amount", wrAmount, ResultType.NEUTRAL,
-                ResultUnit.BYTE);
-        Stat.StatResult stat = Stat.getStat(mbps);
-        getReportLog().printSummary("write throughput", stat.mAverage, ResultType.HIGHER_BETTER,
-                ResultUnit.MBPS);
-    }
-
-    @TimeoutReq(minutes = 60)
-    public void testSingleSequentialUpdate() throws Exception {
-        final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), BUFFER_SIZE);
-        if (fileSize == 0) { // not enough space, give up
-            return;
-        }
-        final int NUMBER_REPETITION = 6;
-        FileUtil.doSequentialUpdateTest(getContext(), DIR_SEQ_UPDATE, getReportLog(), fileSize,
-                BUFFER_SIZE, NUMBER_REPETITION);
-    }
-
-    @TimeoutReq(minutes = 30)
-    public void testSingleSequentialRead() throws Exception {
-        final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), BUFFER_SIZE);
-        if (fileSize == 0) { // not enough space, give up
-            return;
-        }
-        long start = System.currentTimeMillis();
-        final File file = FileUtil.createNewFilledFile(getContext(),
-                DIR_SEQ_RD, fileSize);
-        long finish = System.currentTimeMillis();
-        getReportLog().printValue("write throughput for test file of length " + fileSize,
-                ReportLog.calcRatePerSec((double)fileSize / 1024 / 1024, finish - start),
-                ResultType.HIGHER_BETTER, ResultUnit.MBPS);
-
-        final int NUMBER_READ = 10;
-
-        final byte[] data = new byte[BUFFER_SIZE];
-        double[] times = MeasureTime.measure(NUMBER_READ, new MeasureRun() {
-
-            @Override
-            public void run(int i) throws IOException {
-                final FileInputStream in = new FileInputStream(file);
-                long read = 0;
-                while (read < fileSize) {
-                    in.read(data);
-                    read += BUFFER_SIZE;
-                }
-                in.close();
-            }
-        });
-        double[] mbps = ReportLog.calcRatePerSecArray((double)fileSize / 1024 / 1024, times);
-        getReportLog().printArray("read throughput",
-                mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
-        Stat.StatResult stat = Stat.getStat(mbps);
-        getReportLog().printSummary("read throughput", stat.mAverage, ResultType.HIGHER_BETTER,
-                ResultUnit.MBPS);
-    }
-}
diff --git a/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/TestTest.java b/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/TestTest.java
deleted file mode 100644
index 052c054..0000000
--- a/suite/cts/deviceTests/filesystemperf/src/com/android/cts/filesystemperf/TestTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-
-// code for testing, will be removed / moved before release
-
-package com.android.cts.filesystemperf;
-
-import android.cts.util.CtsAndroidTestCase;
-
-/**
- * This class is for testing CTS logging. Will be disabled in release.
- *
- */
-public class TestTest extends CtsAndroidTestCase {
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-    }
-/* code for testing CTS logging. Disabled.
-    @TimeoutReq(minutes = 15)
-    public void testPass() {
-        double[] array = new double[] {1.0, 2.0, 3.0};
-        getReportLog().printArray(" ", array, true);
-        getReportLog().printArray(" ", array, false);
-        getReportLog().printValue(" ", 1.0);
-        getReportLog().printValue(" ", 2.0);
-        getReportLog().printSummary("This should be shown", 0, 0);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testFail() throws Exception {
-        getReportLog().printValue(" ", 1.0);
-        getReportLog().printValue(" ", 2.0);
-        getReportLog().printSummary("This should not be shown", 0, 0);
-        throw new Exception("failed");
-    }
-*/
-}
diff --git a/suite/cts/deviceTests/jank2/Android.mk b/suite/cts/deviceTests/jank2/Android.mk
deleted file mode 100644
index 346297e..0000000
--- a/suite/cts/deviceTests/jank2/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsJankTestCases
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ub-uiautomator ub-janktesthelper
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/suite/cts/deviceTests/jank2/AndroidManifest.xml b/suite/cts/deviceTests/jank2/AndroidManifest.xml
deleted file mode 100644
index a4c8337..0000000
--- a/suite/cts/deviceTests/jank2/AndroidManifest.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="android.cts.jank">
-
-  <application>
-      <uses-library android:name="android.test.runner"/>
-  </application>
-
-  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                   android:targetPackage="android.cts.jank"
-                   android:label="Jank tests">
-        <meta-data android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
-    </instrumentation>
-
-</manifest>
diff --git a/suite/cts/deviceTests/jank2/AndroidTest.xml b/suite/cts/deviceTests/jank2/AndroidTest.xml
deleted file mode 100644
index 2fbbac7..0000000
--- a/suite/cts/deviceTests/jank2/AndroidTest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="CTS Jank test config">
-    <include name="common-config" />
-    <option name="cts-apk-installer:test-file-name" value="CtsDeviceUi.apk" />
-</configuration>
diff --git a/suite/cts/deviceTests/jank2/src/android/cts/jank/CtsJankTestBase.java b/suite/cts/deviceTests/jank2/src/android/cts/jank/CtsJankTestBase.java
deleted file mode 100644
index cb5c122..0000000
--- a/suite/cts/deviceTests/jank2/src/android/cts/jank/CtsJankTestBase.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.jank;
-
-import android.cts.util.DeviceReportLog;
-import android.os.Bundle;
-import android.support.test.jank.JankTestBase;
-import android.support.test.jank.WindowContentFrameStatsMonitor;
-import android.support.test.uiautomator.UiDevice;
-
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-
-public abstract class CtsJankTestBase extends JankTestBase {
-
-    private UiDevice mDevice;
-    private DeviceReportLog mLog;
-
-    @Override
-    public void afterTest(Bundle metrics) {
-        String source = String.format("%s#%s", getClass().getCanonicalName(), getName());
-        mLog.printValue(source, WindowContentFrameStatsMonitor.KEY_AVG_FPS,
-                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_FPS),
-                ResultType.HIGHER_BETTER, ResultUnit.FPS);
-        mLog.printValue(source, WindowContentFrameStatsMonitor.KEY_AVG_LONGEST_FRAME,
-                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_LONGEST_FRAME),
-                ResultType.LOWER_BETTER, ResultUnit.MS);
-        mLog.printValue(source, WindowContentFrameStatsMonitor.KEY_MAX_NUM_JANKY,
-                metrics.getInt(WindowContentFrameStatsMonitor.KEY_MAX_NUM_JANKY),
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-        mLog.printSummary(WindowContentFrameStatsMonitor.KEY_AVG_NUM_JANKY,
-                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_NUM_JANKY),
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mLog = new DeviceReportLog();
-        // fix device orientation
-        mDevice = UiDevice.getInstance(getInstrumentation());
-        mDevice.setOrientationNatural();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mLog.deliverReportToHost(getInstrumentation());
-        // restore device orientation
-        mDevice.unfreezeRotation();
-        super.tearDown();
-    }
-
-    protected UiDevice getUiDevice() {
-        return mDevice;
-    }
-}
diff --git a/suite/cts/deviceTests/jank2/src/android/cts/jank/ui/CtsDeviceJankUi.java b/suite/cts/deviceTests/jank2/src/android/cts/jank/ui/CtsDeviceJankUi.java
deleted file mode 100644
index 884f83c..0000000
--- a/suite/cts/deviceTests/jank2/src/android/cts/jank/ui/CtsDeviceJankUi.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.jank.ui;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.cts.jank.CtsJankTestBase;
-import android.os.SystemClock;
-import android.support.test.jank.JankTest;
-import android.support.test.jank.WindowContentFrameStatsMonitor;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.Until;
-import android.widget.ListView;
-
-import java.io.IOException;
-
-public class CtsDeviceJankUi extends CtsJankTestBase {
-    private final static int NUM_ELEMENTS = 1000;
-    private static final long DEFAULT_ANIMATION_TIME = 2 * 1000;
-    private static final long POST_SCROLL_IDLE_TIME = 2 *1000;
-    private final static String PACKAGE = "com.android.cts.ui";
-    private final static String CLASS = PACKAGE + ".ScrollingActivity";
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // launch the activity as part of the set up
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setComponent(new ComponentName(PACKAGE, CLASS));
-        intent.putExtra("num_elements", NUM_ELEMENTS);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        getInstrumentation().getTargetContext().startActivity(intent);
-        getUiDevice().wait(Until.hasObject(By.pkg(PACKAGE)), DEFAULT_ANIMATION_TIME);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        getUiDevice().pressHome();
-        super.tearDown();
-    }
-
-    @JankTest(expectedFrames=50, defaultIterationCount=5)
-    @WindowContentFrameStatsMonitor
-    public void testScrolling() throws IOException {
-        getUiDevice().findObject(By.clazz(ListView.class)).fling(Direction.DOWN);
-        SystemClock.sleep(POST_SCROLL_IDLE_TIME);
-    }
-}
diff --git a/suite/cts/deviceTests/opengl/Android.mk b/suite/cts/deviceTests/opengl/Android.mk
deleted file mode 100644
index 0708efb..0000000
--- a/suite/cts/deviceTests/opengl/Android.mk
+++ /dev/null
@@ -1,36 +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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
-
-LOCAL_JNI_SHARED_LIBRARIES := libctsopengl_jni
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceOpenGl
-
-LOCAL_SDK_VERSION := 16
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/suite/cts/deviceTests/opengl/AndroidManifest.xml b/suite/cts/deviceTests/opengl/AndroidManifest.xml
deleted file mode 100644
index 05fb5be..0000000
--- a/suite/cts/deviceTests/opengl/AndroidManifest.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.opengl"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-    <uses-sdk
-        android:minSdkVersion="16"
-        android:targetSdkVersion="17" />
-
-    <uses-feature
-        android:glEsVersion="0x00020000"
-        android:required="true" />
-
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
-    <application android:allowBackup="false" >
-        <uses-library android:name="android.test.runner" />
-
-        <activity
-            android:name=".primitive.GLPrimitiveActivity"
-            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
-            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <activity
-            android:name=".reference.GLReferenceActivity"
-            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
-            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <activity
-            android:name=".reference.GLGameActivity"
-            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
-            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
-        </activity>
-    </application>
-
-    <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:label="OpenGL ES 2.0 Benchmark"
-        android:targetPackage="com.android.cts.opengl" />
-
-</manifest>
\ No newline at end of file
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/GLUtils.cpp b/suite/cts/deviceTests/opengl/jni/graphics/GLUtils.cpp
deleted file mode 100644
index ea166a1..0000000
--- a/suite/cts/deviceTests/opengl/jni/graphics/GLUtils.cpp
+++ /dev/null
@@ -1,237 +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.
- */
-
-#include "GLUtils.h"
-#include <stdlib.h>
-#include <sys/time.h>
-
-#include <android/asset_manager_jni.h>
-
-#define LOG_TAG "CTS_OPENGL"
-#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-static JNIEnv* sEnv = NULL;
-static jobject sAssetManager = NULL;
-
-void GLUtils::setEnvAndAssetManager(JNIEnv* env, jobject assetManager) {
-    sEnv = env;
-    sAssetManager = assetManager;
-}
-
-static AAsset* loadAsset(const char* path) {
-    AAssetManager* nativeManager = AAssetManager_fromJava(sEnv, sAssetManager);
-    if (nativeManager == NULL) {
-        return NULL;
-    }
-    return AAssetManager_open(nativeManager, path, AASSET_MODE_UNKNOWN);;
-}
-
-char* GLUtils::openTextFile(const char* path) {
-    AAsset* asset = loadAsset(path);
-    if (asset == NULL) {
-        ALOGE("Couldn't load %s", path);
-        return NULL;
-    }
-    off_t length = AAsset_getLength(asset);
-    char* buffer = new char[length + 1];
-    int num = AAsset_read(asset, buffer, length);
-    AAsset_close(asset);
-    if (num != length) {
-        ALOGE("Couldn't read %s", path);
-        delete[] buffer;
-        return NULL;
-    }
-    buffer[length] = '\0';
-    return buffer;
-}
-
-GLuint GLUtils::loadTexture(const char* path) {
-    GLuint textureId = 0;
-    jclass activityClass = sEnv->FindClass("com/android/cts/opengl/reference/GLGameActivity");
-    if (activityClass == NULL) {
-        ALOGE("Couldn't find activity class");
-        return -1;
-    }
-    jmethodID loadTexture = sEnv->GetStaticMethodID(activityClass, "loadTexture",
-            "(Landroid/content/res/AssetManager;Ljava/lang/String;)I");
-    if (loadTexture == NULL) {
-        ALOGE("Couldn't find loadTexture method");
-        return -1;
-    }
-    jstring pathStr = sEnv->NewStringUTF(path);
-    textureId = sEnv->CallStaticIntMethod(activityClass, loadTexture, sAssetManager, pathStr);
-    sEnv->DeleteLocalRef(pathStr);
-    return textureId;
-}
-
-static int readInt(char* b) {
-    unsigned char* ub = (unsigned char*) b;
-    return (((int) ub[0]) << 24) | (((int) ub[1]) << 16) | (((int) ub[2]) << 8) | ((int) ub[3]);
-}
-
-static float readFloat(char* b) {
-    union {
-        int input;
-        float output;
-    } data;
-    data.input = readInt(b);
-    return data.output;
-}
-
-Mesh* GLUtils::loadMesh(const char* path) {
-    char* buffer = openTextFile(path);
-    if (buffer == NULL) {
-        return NULL;
-    }
-    int index = 0;
-    int numVertices = readInt(buffer + index);
-    index += 4;
-    float* vertices = new float[numVertices * 3];
-    float* normals = new float[numVertices * 3];
-    float* texCoords = new float[numVertices * 2];
-    for (int i = 0; i < numVertices; i++) {
-        // Vertices
-        int vIndex = i * 3;
-        vertices[vIndex + 0] = readFloat(buffer + index);
-        index += 4;
-        vertices[vIndex + 1] = readFloat(buffer + index);
-        index += 4;
-        vertices[vIndex + 2] = readFloat(buffer + index);
-        index += 4;
-        // Normals
-        normals[vIndex + 0] = readFloat(buffer + index);
-        index += 4;
-        normals[vIndex + 1] = readFloat(buffer + index);
-        index += 4;
-        normals[vIndex + 2] = readFloat(buffer + index);
-        index += 4;
-        // Texture Coordinates
-        int tIndex = i * 2;
-        texCoords[tIndex + 0] = readFloat(buffer + index);
-        index += 4;
-        texCoords[tIndex + 1] = readFloat(buffer + index);
-        index += 4;
-    }
-    return new Mesh(vertices, normals, texCoords, numVertices);
-}
-
-// Loads the given source code as a shader of the given type.
-static GLuint loadShader(GLenum shaderType, const char** source) {
-    GLuint shader = glCreateShader(shaderType);
-    if (shader) {
-        glShaderSource(shader, 1, source, NULL);
-        glCompileShader(shader);
-        GLint compiled = 0;
-        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
-        if (!compiled) {
-            GLint infoLen = 0;
-            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
-            if (infoLen > 0) {
-                char* infoLog = (char*) malloc(sizeof(char) * infoLen);
-                glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
-                ALOGE("Error compiling shader:\n%s\n", infoLog);
-                free(infoLog);
-            }
-            glDeleteShader(shader);
-            shader = 0;
-        }
-    }
-    return shader;
-}
-
-GLuint GLUtils::createProgram(const char** vertexSource, const char** fragmentSource) {
-    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource);
-    if (!vertexShader) {
-        return 0;
-    }
-
-    GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
-    if (!fragmentShader) {
-        return 0;
-    }
-
-    GLuint program = glCreateProgram();
-    if (program) {
-        glAttachShader(program, vertexShader);
-        glAttachShader(program, fragmentShader);
-
-        GLint linkStatus;
-        glLinkProgram(program);
-        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
-
-        if (!linkStatus) {
-            GLint infoLen = 0;
-            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
-            if (infoLen > 0) {
-                char* infoLog = (char*) malloc(sizeof(char) * infoLen);
-                glGetProgramInfoLog(program, infoLen, NULL, infoLog);
-                ALOGE("Error linking program:\n%s\n", infoLog);
-                free(infoLog);
-            }
-            glDeleteProgram(program);
-            program = 0;
-        }
-    }
-    return program;
-}
-
-double GLUtils::currentTimeMillis() {
-    struct timeval tv;
-    gettimeofday(&tv, (struct timezone *) NULL);
-    return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
-}
-
-// Rounds a number up to the smallest power of 2 that is greater than or equal to x.
-int GLUtils::roundUpToSmallestPowerOf2(int x) {
-    if (x < 0) {
-        return 0;
-    }
-    --x;
-    x |= x >> 1;
-    x |= x >> 2;
-    x |= x >> 4;
-    x |= x >> 8;
-    x |= x >> 16;
-    return x + 1;
-}
-
-GLuint GLUtils::genTexture(int texWidth, int texHeight, int fill) {
-    GLuint textureId = 0;
-    int w = roundUpToSmallestPowerOf2(texWidth);
-    int h = roundUpToSmallestPowerOf2(texHeight);
-    uint32_t* m = new uint32_t[w * h];
-    if (m != NULL) {
-        uint32_t* d = m;
-        for (int y = 0; y < h; y++) {
-            for (int x = 0; x < w; x++) {
-                if (fill == RANDOM_FILL) {
-                    *d = 0xff000000 | ((y & 0xff) << 16) | ((x & 0xff) << 8) | ((x + y) & 0xff);
-                } else {
-                    *d = 0xff000000 | fill;
-                }
-                d++;
-            }
-        }
-        glGenTextures(1, &textureId);
-        glBindTexture(GL_TEXTURE_2D, textureId);
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    }
-    delete[] m;
-    return textureId;
-}
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp b/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp
deleted file mode 100644
index 856da1e..0000000
--- a/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp
+++ /dev/null
@@ -1,123 +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.
- */
-#include <jni.h>
-
-#include <stdlib.h>
-
-#include <android/native_window.h>
-#include <android/native_window_jni.h>
-
-#include <graphics/GLUtils.h>
-#include <graphics/Renderer.h>
-
-#include "fullpipeline/FullPipelineRenderer.h"
-#include "pixeloutput/PixelOutputRenderer.h"
-#include "shaderperf/ShaderPerfRenderer.h"
-#include "contextswitch/ContextSwitchRenderer.h"
-
-// Holds the current benchmark's renderer.
-Renderer* gRenderer = NULL;
-ANativeWindow* gNativeWindow = NULL;
-
-enum {
-    FULL_PIPELINE_BENCHMARK = 0,
-    PIXEL_OUTPUT_BENCHMARK = 1,
-    SHADER_PERF_BENCHMARK = 2,
-    CONTEXT_SWITCH_BENCHMARK = 3
-};
-
-extern "C" JNIEXPORT jboolean JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_startBenchmark(
-        JNIEnv* env, jclass /*clazz*/, jint workload, jint numFrames, jdoubleArray frameTimes) {
-    if (gRenderer == NULL) {
-        return false;
-    }
-
-    // Sets up the renderer.
-    bool success = gRenderer->setUp(workload);
-
-    // Records the start time.
-    double start = GLUtils::currentTimeMillis();
-
-    // Offscreen renders 100 tiles per frame so reduce the number of frames to render.
-    if (gRenderer->mOffscreen) {
-        numFrames /= Renderer::OFFSCREEN_INNER_FRAMES;
-    }
-
-    // Draw off the screen.
-    for (int i = 0; i < numFrames && success; i++) {
-        // Draw a frame.
-        success = gRenderer->draw();
-    }
-
-    // Records the end time.
-    double end = GLUtils::currentTimeMillis();
-
-    // Sets the times in the Java array.
-    double times[] = {start, end};
-    env->SetDoubleArrayRegion(frameTimes, 0, 2, times);
-
-    success = gRenderer->tearDown() && success;
-    return success;
-}
-
-// The following functions create the renderers for the various benchmarks.
-extern "C" JNIEXPORT void JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupBenchmark(
-        JNIEnv* env, jclass /*clazz*/, jobject surface, jint benchmark,
-        jboolean offscreen) {
-    gNativeWindow = ANativeWindow_fromSurface(env, surface);
-    switch (benchmark) {
-        case FULL_PIPELINE_BENCHMARK:
-            gRenderer = new FullPipelineRenderer(gNativeWindow, offscreen);
-            break;
-        case PIXEL_OUTPUT_BENCHMARK:
-            gRenderer = new PixelOutputRenderer(gNativeWindow, offscreen);
-            break;
-        case SHADER_PERF_BENCHMARK:
-            gRenderer = new ShaderPerfRenderer(gNativeWindow, offscreen);
-            break;
-        case CONTEXT_SWITCH_BENCHMARK:
-            gRenderer = new ContextSwitchRenderer(gNativeWindow, offscreen);
-            break;
-        default:
-            ALOGE("Unknown benchmark '%d'", benchmark);
-            ANativeWindow_release(gNativeWindow);
-            gNativeWindow = NULL;
-            return;
-    }
-
-    // Set up call will log error conditions
-    if (!gRenderer->eglSetUp()) {
-        delete gRenderer;
-        gRenderer = NULL;
-
-        ANativeWindow_release(gNativeWindow);
-        gNativeWindow = NULL;
-    }
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_tearDownBenchmark(
-        JNIEnv* /*env*/, jclass /*clazz*/) {
-    if (gRenderer == NULL) {
-        return;
-    }
-    gRenderer->eglTearDown();
-    delete gRenderer;
-    gRenderer = NULL;
-
-    ANativeWindow_release(gNativeWindow);
-    gNativeWindow = NULL;
-}
diff --git a/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp b/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp
deleted file mode 100644
index dc0b4e2..0000000
--- a/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp
+++ /dev/null
@@ -1,65 +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.
- */
-#include <jni.h>
-
-#include <android/native_window.h>
-#include <android/native_window_jni.h>
-
-#include <graphics/GLUtils.h>
-#include <graphics/Renderer.h>
-
-#include "ReferenceRenderer.h"
-
-extern "C" JNIEXPORT jboolean JNICALL
-Java_com_android_cts_opengl_reference_GLGameActivity_startBenchmark(
-    JNIEnv* env, jclass /*clazz*/, jobject assetManager, jobject surface, jint numFrames,
-        jdoubleArray setUpTimes, jdoubleArray updateTimes, jdoubleArray renderTimes) {
-
-    GLUtils::setEnvAndAssetManager(env, assetManager);
-
-    if (numFrames > (ReferenceRenderer::FRAMES_PER_SCENE * ReferenceRenderer::NUM_SCENES)) {
-        return false;
-    }
-
-    ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface);
-    ReferenceRenderer* renderer = new ReferenceRenderer(nativeWindow);
-    bool success = renderer->eglSetUp();
-    success = renderer->setUp(0) && success;
-    env->SetDoubleArrayRegion(
-            setUpTimes, 0, ReferenceRenderer::NUM_SETUP_TIMES, renderer->mSetUpTimes);
-
-    double updates[numFrames];
-    double renders[numFrames];
-    for (int i = 0; i < numFrames && success; i++) {
-        double t0 = GLUtils::currentTimeMillis();
-        success = renderer->update(i);
-        double t1 = GLUtils::currentTimeMillis();
-        success = success && renderer->draw();
-        double t2 = GLUtils::currentTimeMillis();
-        updates[i] = t1 - t0;
-        renders[i] = t2 - t1;
-    }
-
-    env->SetDoubleArrayRegion(updateTimes, 0, numFrames, updates);
-    env->SetDoubleArrayRegion(renderTimes, 0, numFrames, renders);
-
-    success = renderer->tearDown() && success;
-    renderer->eglTearDown();
-    delete renderer;
-    renderer = NULL;
-
-    ANativeWindow_release(nativeWindow);
-
-    return success;
-}
diff --git a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/GLActivityIntentKeys.java b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/GLActivityIntentKeys.java
deleted file mode 100644
index 9a29caf..0000000
--- a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/GLActivityIntentKeys.java
+++ /dev/null
@@ -1,37 +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.opengl;
-
-public class GLActivityIntentKeys {
-    /**
-     * Holds the name of the benchmark to run.
-     */
-    public final static String INTENT_EXTRA_BENCHMARK_NAME = "benchmark_name";
-    /**
-     * Holds whether or not the benchmark is to be run offscreen.
-     */
-    public final static String INTENT_EXTRA_OFFSCREEN = "offscreen";
-    /**
-     * The number of frames to render for each workload.
-     */
-    public final static String INTENT_EXTRA_NUM_FRAMES = "num_frames";
-    /**
-     * The number of iterations to run, the workload increases with each iteration.
-     */
-    public final static String INTENT_EXTRA_NUM_ITERATIONS = "num_iterations";
-    /**
-     * The number of milliseconds to wait before timing out.
-     */
-    public final static String INTENT_EXTRA_TIMEOUT = "timeout";
-}
diff --git a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/BenchmarkName.java b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/BenchmarkName.java
deleted file mode 100644
index a6bd6db..0000000
--- a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/BenchmarkName.java
+++ /dev/null
@@ -1,24 +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.opengl.primitive;
-
-/**
- * Represents the different primitive benchmarks.
- */
-public enum BenchmarkName {
-    FullPipeline,
-    PixelOutput,
-    ShaderPerf,
-    ContextSwitch;
-}
diff --git a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java
deleted file mode 100644
index 6defdb7..0000000
--- a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java
+++ /dev/null
@@ -1,167 +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.opengl.primitive;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.cts.util.WatchDog;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.Surface;
-
-import com.android.cts.opengl.GLActivityIntentKeys;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Semaphore;
-
-public class GLPrimitiveActivity extends Activity {
-
-    public final static String TAG = "GLPrimitiveActivity";
-
-    private volatile Exception mException;
-    private volatile Surface mSurface = null;
-    private CountDownLatch mStartSignal = new CountDownLatch(1);
-    private Semaphore mSemaphore = new Semaphore(0);
-
-    private BenchmarkName mBenchmark;
-    private boolean mOffscreen;
-    private int mNumFrames;
-    private int mNumIterations;
-    private int mTimeout;
-    public double[] mFpsValues;
-
-    @Override
-    public void onCreate(Bundle data) {
-        super.onCreate(data);
-        System.loadLibrary("ctsopengl_jni");
-        Intent intent = getIntent();
-        mBenchmark = BenchmarkName.valueOf(
-                intent.getStringExtra(GLActivityIntentKeys.INTENT_EXTRA_BENCHMARK_NAME));
-        mOffscreen = intent.getBooleanExtra(GLActivityIntentKeys.INTENT_EXTRA_OFFSCREEN, false);
-        mNumFrames = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, 0);
-        mNumIterations = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_ITERATIONS, 0);
-        mTimeout = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, 0);
-        mFpsValues = new double[mNumIterations];
-
-        Log.i(TAG, "Benchmark: " + mBenchmark);
-        Log.i(TAG, "Offscreen: " + mOffscreen);
-        Log.i(TAG, "Num Frames: " + mNumFrames);
-        Log.i(TAG, "Num Iterations: " + mNumIterations);
-        Log.i(TAG, "Time Out: " + mTimeout);
-
-        SurfaceView surfaceView = new SurfaceView(this);
-        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
-            @Override
-            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-                mSurface = holder.getSurface();
-                mStartSignal.countDown();
-            }
-
-            @Override
-            public void surfaceCreated(SurfaceHolder holder) {}
-
-            @Override
-            public void surfaceDestroyed(SurfaceHolder holder) {}
-        });
-        setContentView(surfaceView);
-        // Spawns a worker to run the benchmark.
-        Worker worker = new Worker();
-        worker.start();
-    }
-
-    public void waitForCompletion() throws Exception {
-        // Wait for semiphore.
-        mSemaphore.acquire();
-        if (mException != null) {
-            throw mException;
-        }
-    }
-
-    private void complete() {
-        // Release semiphore.
-        mSemaphore.release();
-        finish();
-    }
-
-    private synchronized void setException(Exception e) {
-        if (mException == null) {
-            mException = e;
-        }
-    }
-
-    private static native boolean setupBenchmark(
-            Surface surface, int benchmark, boolean offscreen);
-
-    private static native boolean startBenchmark(int workload, int numFrames, double[] frameTimes);
-
-    private static native void tearDownBenchmark();
-
-    /**
-     * This thread runs the benchmarks, freeing the UI thread.
-     */
-    private class Worker extends Thread implements WatchDog.TimeoutCallback {
-
-        private WatchDog watchDog;
-        private volatile boolean success = true;
-
-        @Override
-        public void run() {
-            try {
-                mStartSignal.await();
-            } catch (InterruptedException e) {
-                setException(e);
-                complete();
-                return;
-            }
-            Log.i(TAG, mBenchmark + " Benchmark Started");
-            // Creates a watchdog to ensure a iteration doesn't exceed the timeout.
-            watchDog = new WatchDog(mTimeout, this);
-            // Used to record the start and end time of the iteration.
-            double[] times = new double[2];
-            try {
-                // Setup the benchmark.
-                setupBenchmark(mSurface, mBenchmark.ordinal(), mOffscreen);
-                for (int i = 0; i < mNumIterations && success; i++) {
-                    // The workload to use for this iteration.
-                    int workload = i + 1;
-                    watchDog.start();
-                    // Start benchmark.
-                    success = startBenchmark(workload, mNumFrames, times);
-                    watchDog.stop();
-                    if (!success) {
-                        setException(new Exception("Benchmark failed to run"));
-                    } else {
-                        // Calculate FPS.
-                        mFpsValues[i] = mNumFrames * 1000.0f / (times[1] - times[0]);
-                    }
-                }
-            }
-            finally
-            {
-                tearDownBenchmark();
-            }
-
-            complete();
-            Log.i(TAG, mBenchmark + " Benchmark Completed");
-        }
-
-        public void onTimeout() {
-            setException(new Exception("Benchmark timed out"));
-            complete();
-        }
-
-    }
-}
diff --git a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveBenchmark.java b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveBenchmark.java
deleted file mode 100644
index c177129..0000000
--- a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveBenchmark.java
+++ /dev/null
@@ -1,141 +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.opengl.primitive;
-
-import com.android.cts.opengl.GLActivityIntentKeys;
-import android.cts.util.CtsActivityInstrumentationTestCase2;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-
-import android.content.Intent;
-import com.android.cts.util.TimeoutReq;
-
-/**
- * Runs the Primitive OpenGL ES 2.0 Benchmarks.
- */
-public class GLPrimitiveBenchmark extends CtsActivityInstrumentationTestCase2<GLPrimitiveActivity> {
-
-    private static final int NUM_FRAMES = 100;
-    private static final int NUM_ITERATIONS = 8;
-    private static final int TIMEOUT = 1000000;
-
-    public GLPrimitiveBenchmark() {
-        super(GLPrimitiveActivity.class);
-    }
-
-    /**
-     * Runs the full OpenGL ES 2.0 pipeline test offscreen.
-     */
-    @TimeoutReq(minutes = 100)
-    public void testFullPipelineOffscreen() throws Exception {
-        runBenchmark(BenchmarkName.FullPipeline, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
-    }
-
-    /**
-     * Runs the full OpenGL ES 2.0 pipeline test onscreen.
-     */
-    @TimeoutReq(minutes = 100)
-    public void testFullPipelineOnscreen() throws Exception {
-        runBenchmark(BenchmarkName.FullPipeline, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
-    }
-
-    /**
-     * Runs the pixel output test offscreen.
-     */
-    @TimeoutReq(minutes = 100)
-    public void testPixelOutputOffscreen() throws Exception {
-        runBenchmark(BenchmarkName.PixelOutput, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
-    }
-
-    /**
-     * Runs the pixel output test onscreen.
-     */
-    @TimeoutReq(minutes = 100)
-    public void testPixelOutputOnscreen() throws Exception {
-        runBenchmark(BenchmarkName.PixelOutput, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
-    }
-
-    /**
-     * Runs the shader performance test offscreen.
-     */
-    @TimeoutReq(minutes = 100)
-    public void testShaderPerfOffscreen() throws Exception {
-        runBenchmark(BenchmarkName.ShaderPerf, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
-    }
-
-    /**
-     * Runs the shader performance test onscreen.
-     */
-    @TimeoutReq(minutes = 100)
-    public void testShaderPerfOnscreen() throws Exception {
-        runBenchmark(BenchmarkName.ShaderPerf, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
-    }
-
-    /**
-     * Runs the context switch overhead test offscreen.
-     */
-    @TimeoutReq(minutes = 100)
-    public void testContextSwitchOffscreen() throws Exception {
-        runBenchmark(BenchmarkName.ContextSwitch, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
-    }
-
-    /**
-     * Runs the context switch overhead test onscreen.
-     */
-    @TimeoutReq(minutes = 100)
-    public void testContextSwitchOnscreen() throws Exception {
-        runBenchmark(BenchmarkName.ContextSwitch, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
-    }
-
-    /**
-     * Runs the specified test.
-     *
-     * @param benchmark An enum representing the benchmark to run.
-     * @param offscreen Whether to render to an offscreen framebuffer rather than the screen.
-     * @param numFrames The number of frames to render.
-     * @param numIterations The number of iterations to run, each iteration has a bigger workload.
-     * @param timeout The milliseconds to wait for an iteration of the benchmark before timing out.
-     * @throws Exception If the benchmark could not be run.
-     */
-    private void runBenchmark(BenchmarkName benchmark, boolean offscreen, int numFrames,
-            int numIterations, int timeout) throws Exception {
-        String benchmarkName = benchmark.toString();
-        Intent intent = new Intent();
-        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_BENCHMARK_NAME, benchmarkName);
-        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_OFFSCREEN, offscreen);
-        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, numFrames);
-        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_ITERATIONS, numIterations);
-        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, timeout);
-
-        setActivityIntent(intent);
-        GLPrimitiveActivity activity = getActivity();
-        if (activity != null) {
-            activity.waitForCompletion();
-            double[] fpsValues = activity.mFpsValues;
-            double score = 0;
-            for (double d : fpsValues) {
-                score += d;
-            }
-            score /= numIterations;// Average.
-
-            // TODO: maybe standard deviation / RMSE will be useful?
-
-            getReportLog().printArray(
-                    "Fps Values", fpsValues, ResultType.HIGHER_BETTER, ResultUnit.FPS);
-            getReportLog().printSummary(
-                    "Average Frames Per Second", score, ResultType.HIGHER_BETTER,
-                    ResultUnit.SCORE);
-        }
-    }
-}
diff --git a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/reference/GLGameActivity.java b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/reference/GLGameActivity.java
deleted file mode 100644
index 3b310f9..0000000
--- a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/reference/GLGameActivity.java
+++ /dev/null
@@ -1,180 +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.opengl.reference;
-
-import com.android.cts.opengl.GLActivityIntentKeys;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.res.AssetManager;
-import android.cts.util.WatchDog;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.opengl.GLES20;
-import android.opengl.GLUtils;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.concurrent.CountDownLatch;
-
-public class GLGameActivity extends Activity {
-
-    public final static String SET_UP_TIME = "set_up_time";
-    public final static String UPDATE_TIMES = "update_times";
-    public final static String RENDER_TIMES = "render_times";
-
-    private int mNumFrames;
-    private int mTimeout;
-    private double[] mSetUpTimes;
-    private double[] mUpdateTimes;
-    private double[] mRenderTimes;
-    private volatile Surface mSurface = null;
-    private CountDownLatch mStartSignal = new CountDownLatch(1);
-
-    @Override
-    public void onCreate(Bundle data) {
-        super.onCreate(data);
-        System.loadLibrary("ctsopengl_jni");
-
-        Intent intent = getIntent();
-        mNumFrames = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, 1000);
-        mTimeout = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, 1000000);
-
-        SurfaceView surfaceView = new SurfaceView(this);
-        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
-            @Override
-            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-                mSurface = holder.getSurface();
-                mStartSignal.countDown();
-            }
-
-            @Override
-            public void surfaceCreated(SurfaceHolder holder) {}
-
-            @Override
-            public void surfaceDestroyed(SurfaceHolder holder) {}
-        });
-        setContentView(surfaceView);
-
-        // Spawns a worker.
-        Worker worker = new Worker(new Handler() {
-            public void handleMessage(Message msg) {
-                Intent intent = new Intent();
-                intent.putExtra(SET_UP_TIME, mSetUpTimes);
-                intent.putExtra(UPDATE_TIMES, mUpdateTimes);
-                intent.putExtra(RENDER_TIMES, mRenderTimes);
-                setResult((msg.what == 1) ? RESULT_OK : RESULT_CANCELED, intent);
-                finish();
-            }
-        });
-        worker.start();
-    }
-
-    private static native boolean startBenchmark(AssetManager manager,
-            Surface surface,
-            int numFrames,
-            double[] setUpTimes,
-            double[] updateTimes,
-            double[] renderTimes);
-
-    /**
-     * This thread renderers the benchmarks, freeing the UI thread.
-     */
-    private class Worker extends Thread implements WatchDog.TimeoutCallback {
-
-        private WatchDog watchDog;
-        private Handler mHandler;
-
-        public Worker(Handler handler) {
-            mHandler = handler;
-        }
-
-        @Override
-        public void run() {
-            try {
-                mStartSignal.await();
-            } catch (InterruptedException e) {
-                mHandler.sendEmptyMessage(0);
-                return;
-            }
-            // Creates a watchdog to ensure a iteration doesn't exceed the timeout.
-            watchDog = new WatchDog(mTimeout, this);
-            watchDog.start();
-
-            // Used to record the time taken to setup (GL, context, textures, meshes).
-            mSetUpTimes = new double[4];
-            // Used to record the times taken to update.
-            mUpdateTimes = new double[mNumFrames];
-            // Used to record the times taken to render.
-            mRenderTimes = new double[mNumFrames];
-            boolean success = startBenchmark(getAssets(),
-                    mSurface,
-                    mNumFrames,
-                    mSetUpTimes,
-                    mUpdateTimes,
-                    mRenderTimes);
-
-            watchDog.stop();
-            mHandler.sendEmptyMessage((success) ? 1 : 0);
-        }
-
-        public void onTimeout() {
-            mHandler.sendEmptyMessage(0);
-        }
-
-    }
-
-    public static int loadTexture(AssetManager manager, String path) {
-        InputStream in = null;
-        try {
-            in = manager.open(path);
-        } catch (IOException e) {
-            e.printStackTrace();
-            return -1;
-        }
-        BitmapFactory.Options op = new BitmapFactory.Options();
-        op.inPreferredConfig = Bitmap.Config.ARGB_8888;
-        Bitmap bmp = BitmapFactory.decodeStream(in, null, op);
-        // generate textureID
-        int[] textures = new int[1];
-        GLES20.glGenTextures(1, textures, 0);
-        int textureID = textures[0];
-
-        // create texture
-        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
-        GLES20.glTexParameteri(
-                GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
-        GLES20.glTexParameteri(
-                GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
-        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
-        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
-        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
-
-        // clean up
-        try {
-            in.close();
-        } catch (IOException e) {
-            e.printStackTrace();
-        } finally {
-            bmp.recycle();
-        }
-        return textureID;
-    }
-}
diff --git a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/reference/GLReferenceActivity.java b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/reference/GLReferenceActivity.java
deleted file mode 100644
index 8d34535..0000000
--- a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/reference/GLReferenceActivity.java
+++ /dev/null
@@ -1,82 +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.opengl.reference;
-
-import com.android.cts.opengl.GLActivityIntentKeys;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-import java.util.concurrent.Semaphore;
-
-public class GLReferenceActivity extends Activity {
-
-    private final static int GAME_ACTIVITY_CODE = 1;
-
-    private volatile Exception mException;
-    private int mNumFrames;
-    private int mTimeout;
-
-    public double[] mSetUpTimes;
-    public double[] mUpdateTimes;
-    public double[] mRenderTimes;
-
-    private Semaphore mSemaphore = new Semaphore(0);
-
-    @Override
-    public void onCreate(Bundle data) {
-        super.onCreate(data);
-        Intent intent = getIntent();
-        mNumFrames = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, 0);
-        mTimeout = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, 0);
-
-        // Start benchmark
-        intent = new Intent(this, GLGameActivity.class);
-        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, mNumFrames);
-        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, mTimeout);
-        startActivityForResult(intent, GAME_ACTIVITY_CODE);
-    }
-
-    public void waitForCompletion() throws Exception {
-        // Wait for semiphore.
-        mSemaphore.acquire();
-        if (mException != null) {
-            throw mException;
-        }
-    }
-
-    private synchronized void setException(Exception e) {
-        if (mException == null) {
-            mException = e;
-        }
-    }
-
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == GAME_ACTIVITY_CODE) {
-            if (resultCode == RESULT_OK) {
-                // Benchmark passed
-                mSetUpTimes = data.getDoubleArrayExtra(GLGameActivity.SET_UP_TIME);
-                mUpdateTimes = data.getDoubleArrayExtra(GLGameActivity.UPDATE_TIMES);
-                mRenderTimes = data.getDoubleArrayExtra(GLGameActivity.RENDER_TIMES);
-            } else {
-                setException(new Exception("Benchmark failed to run"));
-            }
-            // Release semiphore.
-            mSemaphore.release();
-            finish();
-        }
-    }
-
-}
diff --git a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/reference/GLReferenceBenchmark.java b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/reference/GLReferenceBenchmark.java
deleted file mode 100644
index fdea916..0000000
--- a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/reference/GLReferenceBenchmark.java
+++ /dev/null
@@ -1,86 +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.opengl.reference;
-
-import com.android.cts.opengl.GLActivityIntentKeys;
-
-import android.cts.util.CtsActivityInstrumentationTestCase2;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.cts.util.TimeoutReq;
-
-import android.content.Intent;
-
-/**
- * Runs the Reference OpenGL ES 2.0 Benchmark.
- */
-public class GLReferenceBenchmark extends CtsActivityInstrumentationTestCase2<GLReferenceActivity> {
-
-    private static final int NUM_FRAMES_PER_SCENE = 500;
-    private static final int NUM_SCENES = 2;
-    private static final int NUM_FRAMES = NUM_FRAMES_PER_SCENE * NUM_SCENES;
-    private static final int TIMEOUT = 1000000;
-
-    public GLReferenceBenchmark() {
-        super(GLReferenceActivity.class);
-    }
-
-    /**
-     * Runs the reference benchmark.
-     */
-    @TimeoutReq(minutes = 30)
-    public void testReferenceBenchmark() throws Exception {
-        Intent intent = new Intent();
-        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, NUM_FRAMES);
-        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, TIMEOUT);
-
-        GLReferenceActivity activity = null;
-        setActivityIntent(intent);
-        activity = getActivity();
-        if (activity != null) {
-            activity.waitForCompletion();
-            double totalTime = 0;
-            double[] setUpTimes = activity.mSetUpTimes;
-            double[] updateTimes = activity.mUpdateTimes;
-            double[] renderTimes = activity.mRenderTimes;
-
-            // Calculate update and render average.
-            double updateSum = updateTimes[0];
-            double renderSum = renderTimes[0];
-            for (int i = 0; i < NUM_FRAMES - 1; i++) {
-                updateSum += updateTimes[i + 1];
-                renderSum += renderTimes[i + 1];
-            }
-            double updateAverage = updateSum / NUM_FRAMES;
-            double renderAverage = renderSum / NUM_FRAMES;
-
-            getReportLog().printArray(
-                    "Set Up Times", setUpTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-            getReportLog().printArray(
-                    "Update Times", updateTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-            getReportLog().printValue(
-                    "Update Time Average", updateAverage, ResultType.LOWER_BETTER,
-                    ResultUnit.MS);
-            getReportLog().printArray(
-                    "Render Times", renderTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-            getReportLog().printValue(
-                    "Render Time Average", renderAverage, ResultType.LOWER_BETTER,
-                    ResultUnit.MS);
-            totalTime = setUpTimes[0] + setUpTimes[1] + setUpTimes[2] +
-                    setUpTimes[3] + updateAverage + renderAverage;
-            getReportLog().printSummary(
-                    "Total Time", totalTime, ResultType.LOWER_BETTER, ResultUnit.MS);
-        }
-    }
-}
diff --git a/suite/cts/deviceTests/simplecpu/Android.mk b/suite/cts/deviceTests/simplecpu/Android.mk
deleted file mode 100644
index 17e7506..0000000
--- a/suite/cts/deviceTests/simplecpu/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
-
-LOCAL_JNI_SHARED_LIBRARIES := libctscpu_jni
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceSimpleCpu
-
-LOCAL_SDK_VERSION := 16
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/suite/cts/deviceTests/simplecpu/AndroidManifest.xml b/suite/cts/deviceTests/simplecpu/AndroidManifest.xml
deleted file mode 100644
index e5c1c2b..0000000
--- a/suite/cts/deviceTests/simplecpu/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.simplecpu">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.simplecpu"
-            android:label="Very simple CPU benchmarking" />
-</manifest>
diff --git a/suite/cts/deviceTests/simplecpu/jni/CpuNativeJni.cpp b/suite/cts/deviceTests/simplecpu/jni/CpuNativeJni.cpp
deleted file mode 100644
index e0be7f3..0000000
--- a/suite/cts/deviceTests/simplecpu/jni/CpuNativeJni.cpp
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * 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.
- */
-
-#include <jni.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-
-/* Code from now to qsort_local all copied from bionic source.
- * The code is duplicated here to remove dependency on optimized bionic
- */
-static __inline char    *med3(char *, char *, char *, int (*)(const void *, const void *));
-static __inline void     swapfunc(char *, char *, int, int);
-
-#define min(a, b)   (a) < (b) ? a : b
-
-/*
- * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
- */
-#define swapcode(TYPE, parmi, parmj, n) {       \
-    long i = (n) / sizeof (TYPE);           \
-    TYPE *pi = (TYPE *) (parmi);            \
-    TYPE *pj = (TYPE *) (parmj);            \
-    do {                        \
-        TYPE    t = *pi;            \
-        *pi++ = *pj;                \
-        *pj++ = t;              \
-        } while (--i > 0);              \
-}
-
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
-    es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
-
-static __inline void
-swapfunc(char *a, char *b, int n, int swaptype)
-{
-    if (swaptype <= 1)
-        swapcode(long, a, b, n)
-    else
-        swapcode(char, a, b, n)
-}
-
-#define swap(a, b)                  \
-    if (swaptype == 0) {                \
-        long t = *(long *)(a);          \
-        *(long *)(a) = *(long *)(b);        \
-        *(long *)(b) = t;           \
-    } else                      \
-        swapfunc(a, b, es, swaptype)
-
-#define vecswap(a, b, n)    if ((n) > 0) swapfunc(a, b, n, swaptype)
-
-static __inline char *
-med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
-{
-    return cmp(a, b) < 0 ?
-           (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
-              :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
-}
-
-void
-qsort_local(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *))
-{
-    char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
-    int d, r, swaptype, swap_cnt;
-    char *a = (char*)aa;
-
-loop:   SWAPINIT(a, es);
-    swap_cnt = 0;
-    if (n < 7) {
-        for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
-            for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
-                 pl -= es)
-                swap(pl, pl - es);
-        return;
-    }
-    pm = (char *)a + (n / 2) * es;
-    if (n > 7) {
-        pl = (char *)a;
-        pn = (char *)a + (n - 1) * es;
-        if (n > 40) {
-            d = (n / 8) * es;
-            pl = med3(pl, pl + d, pl + 2 * d, cmp);
-            pm = med3(pm - d, pm, pm + d, cmp);
-            pn = med3(pn - 2 * d, pn - d, pn, cmp);
-        }
-        pm = med3(pl, pm, pn, cmp);
-    }
-    swap(a, pm);
-    pa = pb = (char *)a + es;
-
-    pc = pd = (char *)a + (n - 1) * es;
-    for (;;) {
-        while (pb <= pc && (r = cmp(pb, a)) <= 0) {
-            if (r == 0) {
-                swap_cnt = 1;
-                swap(pa, pb);
-                pa += es;
-            }
-            pb += es;
-        }
-        while (pb <= pc && (r = cmp(pc, a)) >= 0) {
-            if (r == 0) {
-                swap_cnt = 1;
-                swap(pc, pd);
-                pd -= es;
-            }
-            pc -= es;
-        }
-        if (pb > pc)
-            break;
-        swap(pb, pc);
-        swap_cnt = 1;
-        pb += es;
-        pc -= es;
-    }
-    if (swap_cnt == 0) {  /* Switch to insertion sort */
-        for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
-            for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
-                 pl -= es)
-                swap(pl, pl - es);
-        return;
-    }
-
-    pn = (char *)a + n * es;
-    r = min(pa - (char *)a, pb - pa);
-    vecswap(a, pb - r, r);
-    r = min(pd - pc, pn - pd - (int)es);
-    vecswap(pb, pn - r, r);
-    if ((r = pb - pa) > (int)es)
-        qsort_local(a, r / es, es, cmp);
-    if ((r = pd - pc) > (int)es) {
-        /* Iterate rather than recurse to save stack space */
-        a = pn - r;
-        n = r / es;
-        goto loop;
-    }
-    /* qsort(pn - r, r / es, es, cmp); */
-}
-
-/* code duplication ends here */
-
-/**
- * Util for getting time stamp
- */
-double currentTimeMillis()
-{
-    struct timeval tv;
-    gettimeofday(&tv, (struct timezone *) NULL);
-    return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
-}
-
-/**
- * Initialize given array randomly for the given seed
- */
-template <typename T> void randomInitArray(T* array, int len, unsigned int seed)
-{
-    srand(seed);
-    for (int i = 0; i < len; i++) {
-        array[i] = (T) rand();
-    }
-}
-
-/**
- * comparison function for int, for qsort
- */
-int cmpint(const void* p1, const void* p2)
-{
-    return *(int*)p1 - *(int*)p2;
-}
-
-extern "C" JNIEXPORT jdouble JNICALL Java_com_android_cts_simplecpu_CpuNative_runSort(JNIEnv* env,
-        jclass clazz, jint numberElements, jint repetition)
-{
-    int* data = new int[numberElements];
-    if (data == NULL) {
-        env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), "No memory");
-        return -1;
-    }
-    double totalTime = 0;
-    for (int i = 0; i < repetition; i++) {
-        randomInitArray<int>(data, numberElements, 0);
-        double start = currentTimeMillis();
-        qsort_local(data, numberElements, sizeof(int), cmpint);
-        double end = currentTimeMillis();
-        totalTime += (end - start);
-    }
-    delete[] data;
-    return totalTime;
-}
-
-
-/**
- * Do matrix multiplication, C = A x B with all matrices having dimension of n x n
- * The implementation is not in the most efficient, but it is good enough for benchmarking purpose.
- * @param n should be multiple of 8
- */
-void doMatrixMultiplication(float* A, float* B, float* C, int n)
-{
-    // batch size
-    const int M = 8;
-    for (int i = 0; i < n; i++) {
-        for (int j = 0; j < n; j += M) {
-            float sum[M];
-            for (int k = 0; k < M; k++) {
-                sum[k] = 0;
-            }
-            // re-use the whole cache line for accessing B.
-            // otherwise, the whole line will be read and only one value will be used.
-
-            for (int k = 0; k < n; k++) {
-                float a = A[i * n + k];
-                sum[0] += a * B[k * n + j];
-                sum[1] += a * B[k * n + j + 1];
-                sum[2] += a * B[k * n + j + 2];
-                sum[3] += a * B[k * n + j + 3];
-                sum[4] += a * B[k * n + j + 4];
-                sum[5] += a * B[k * n + j + 5];
-                sum[6] += a * B[k * n + j + 6];
-                sum[7] += a * B[k * n + j + 7];
-            }
-            for (int k = 0; k < M; k++) {
-                C[i * n + j + k] = sum[k];
-            }
-        }
-    }
-}
-
-extern "C" JNIEXPORT jdouble JNICALL Java_com_android_cts_simplecpu_CpuNative_runMatrixMultiplication(
-        JNIEnv* env, jclass clazz, jint n, jint repetition)
-{
-    // C = A x B
-    float* A = new float[n * n];
-    float* B = new float[n * n];
-    float* C = new float[n * n];
-    if ((A == NULL) || (B == NULL) || (C == NULL)) {
-        delete[] A;
-        delete[] B;
-        delete[] C;
-        env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), "No memory");
-        return -1;
-    }
-    double totalTime = 0;
-    for (int i = 0; i < repetition; i++) {
-        randomInitArray<float>(A, n * n, 0);
-        randomInitArray<float>(B, n * n, 1);
-        double start = currentTimeMillis();
-        doMatrixMultiplication(A, B, C, n);
-        double end = currentTimeMillis();
-        totalTime += (end - start);
-    }
-    delete[] A;
-    delete[] B;
-    delete[] C;
-    return totalTime;
-}
-
diff --git a/suite/cts/deviceTests/simplecpu/src/com/android/cts/simplecpu/CpuNative.java b/suite/cts/deviceTests/simplecpu/src/com/android/cts/simplecpu/CpuNative.java
deleted file mode 100644
index 8b48623..0000000
--- a/suite/cts/deviceTests/simplecpu/src/com/android/cts/simplecpu/CpuNative.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.simplecpu;
-
-public class CpuNative {
-    static {
-        System.loadLibrary("ctscpu_jni");
-    }
-    /**
-     * run qsort for given number of repetition
-     * with each having the size of bufferSize.
-     * @param numberElements
-     * @param repeatition
-     * @return time taken for computation, added for all repetition in ms
-     */
-    public static native double runSort(int numberElements, int repetition);
-
-    /**
-     * run matrix multiplication of (n x n) x (n x n)
-     *
-     * @param n dimension, should be multiple of 8
-     * @param repetition
-     * @return time taken for computation, added for all repetition in ms
-     */
-    public static native double runMatrixMultiplication(int n, int repetition);
-}
diff --git a/suite/cts/deviceTests/simplecpu/src/com/android/cts/simplecpu/SimpleCpuTest.java b/suite/cts/deviceTests/simplecpu/src/com/android/cts/simplecpu/SimpleCpuTest.java
deleted file mode 100644
index ce0feac..0000000
--- a/suite/cts/deviceTests/simplecpu/src/com/android/cts/simplecpu/SimpleCpuTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.simplecpu;
-
-import android.util.Log;
-
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import android.cts.util.CtsAndroidTestCase;
-import com.android.cts.util.Stat;
-import com.android.cts.util.TimeoutReq;
-
-/**
- * Very simple CPU benchmarking to check the basic capability of CPU.
- * Cases include
- *   qsort
- *   matrix multiplication (for floating point performance)
- */
-public class SimpleCpuTest extends CtsAndroidTestCase {
-    private static final String TAG = "BandwidthTest";
-    private static final int KB = 1024;
-    private static final int MB = 1024 * 1024;
-    private static final int NUMBER_REPEAT = 20;
-    // reject data outside +/- this value * median
-    private static final double OUTLIER_THRESHOLD = 0.1;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        warmUpCpu();
-    }
-
-    public void testSort004KB() {
-        doTestSort(NUMBER_REPEAT, 4 * KB);
-    }
-
-    public void testSort128KB() {
-        doTestSort(NUMBER_REPEAT, 128 * KB);
-    }
-
-    public void testSort001MB() {
-        doTestSort(NUMBER_REPEAT, 1 * MB);
-    }
-
-    // will fit into L1
-    public void testMatrixMultiplication032() {
-        doMatrixMultiplication(NUMBER_REPEAT, 32);
-    }
-
-    // mostly fit into L2
-    public void testMatrixMultiplication128() {
-        doMatrixMultiplication(NUMBER_REPEAT, 128);
-    }
-
-    // may fit into L2
-    public void testMatrixMultiplication200() {
-        doMatrixMultiplication(NUMBER_REPEAT, 200);
-    }
-
-    public void testMatrixMultiplication400() {
-        doMatrixMultiplication(NUMBER_REPEAT, 400);
-    }
-
-    // will exceed L2
-    @TimeoutReq(minutes = 30)
-    public void testMatrixMultiplication600() {
-        doMatrixMultiplication(NUMBER_REPEAT, 600);
-    }
-
-    /**
-     * run some code to force full CPU freq.
-     */
-    private void warmUpCpu() {
-        CpuNative.runSort(1 * MB, 10);
-    }
-
-    /**
-     * qsort test
-     * @param numberRepeat
-     * @param arrayLength
-     */
-    private void doTestSort(int numberRepeat, int arrayLength) {
-        final int numberRepeatInEachCall = 10;
-        double[] result = new double[numberRepeat];
-        for (int i = 0; i < numberRepeat; i++) {
-            result[i] = CpuNative.runSort(arrayLength, numberRepeatInEachCall);
-        }
-        getReportLog().printArray("sorting time", result, ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-        Stat.StatResult stat = Stat.getStatWithOutlierRejection(result, OUTLIER_THRESHOLD);
-        if (stat.mDataCount != result.length) {
-            Log.w(TAG, "rejecting " + (result.length - stat.mDataCount) + " outliers");
-        }
-        getReportLog().printSummary("sorting time", stat.mAverage, ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-    }
-
-    /**
-     * Matrix multiplication test, nxn matrix multiplication
-     * @param numberRepeat
-     * @param n should be multiple of 8
-     */
-    private void doMatrixMultiplication(int numberRepeat, int n) {
-        assertTrue(n % 8 == 0);
-        final int numberRepeatInEachCall = 10;
-        double[] result = new double[numberRepeat];
-        for (int i = 0; i < numberRepeat; i++) {
-            result[i] = CpuNative.runMatrixMultiplication(n, numberRepeatInEachCall);
-        }
-        getReportLog().printArray("matrix mutiplication time", result, ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-        Stat.StatResult stat = Stat.getStatWithOutlierRejection(result, OUTLIER_THRESHOLD);
-        if (stat.mDataCount != result.length) {
-            Log.w(TAG, "rejecting " + (result.length - stat.mDataCount) + " outliers");
-        }
-        getReportLog().printSummary("matrix mutiplication time", stat.mAverage,
-                ResultType.LOWER_BETTER, ResultUnit.MS);
-    }
-
-}
diff --git a/suite/cts/deviceTests/tvproviderperf/Android.mk b/suite/cts/deviceTests/tvproviderperf/Android.mk
deleted file mode 100644
index e268955..0000000
--- a/suite/cts/deviceTests/tvproviderperf/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceTvProviderPerf
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
-
diff --git a/suite/cts/deviceTests/tvproviderperf/AndroidManifest.xml b/suite/cts/deviceTests/tvproviderperf/AndroidManifest.xml
deleted file mode 100644
index d345ab2..0000000
--- a/suite/cts/deviceTests/tvproviderperf/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.tvproviderperf">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-    <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
-    <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.tvproviderperf"
-            android:label="TvProvider performance measurement" />
-</manifest>
diff --git a/suite/cts/deviceTests/tvproviderperf/src/com/android/cts/tvproviderperf/TvProviderPerfTest.java b/suite/cts/deviceTests/tvproviderperf/src/com/android/cts/tvproviderperf/TvProviderPerfTest.java
deleted file mode 100644
index 8eef86d..0000000
--- a/suite/cts/deviceTests/tvproviderperf/src/com/android/cts/tvproviderperf/TvProviderPerfTest.java
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * 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.tvproviderperf;
-
-import android.content.ComponentName;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.OperationApplicationException;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.cts.util.CtsAndroidTestCase;
-import android.media.tv.TvContract;
-import android.media.tv.TvContract.Channels;
-import android.media.tv.TvContract.Programs;
-import android.net.Uri;
-import android.os.RemoteException;
-
-import com.android.cts.util.MeasureRun;
-import com.android.cts.util.MeasureTime;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.TimeoutReq;
-import com.android.cts.util.Stat;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Test performance of TvProvider on a device. TvProvider typically handles hundreds of
- * thousands of records periodically, so it is desirable to have performance under a reasonable
- * bar.
- */
-public class TvProviderPerfTest extends CtsAndroidTestCase {
-    private static final int TRANSACTION_RUNS = 100;
-    private static final int QUERY_RUNS = 10;
-
-    private ContentResolver mContentResolver;
-    private String mInputId;
-    private boolean mHasTvInputFramework;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mHasTvInputFramework = getContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_LIVE_TV);
-        if (!mHasTvInputFramework) return;
-        mContentResolver = getContext().getContentResolver();
-        mInputId = TvContract.buildInputId(new ComponentName(getContext(), getClass()));
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        try {
-            if (!mHasTvInputFramework) return;
-            mContentResolver.delete(Programs.CONTENT_URI, null, null);
-            mContentResolver.delete(Channels.CONTENT_URI, null, null);
-        } finally {
-            super.tearDown();
-        }
-    }
-
-    @TimeoutReq(minutes = 8)
-    public void testChannels() throws Exception {
-        if (!mHasTvInputFramework) return;
-        double[] averages = new double[5];
-
-        // Insert
-        final ArrayList<ContentProviderOperation> operations = new ArrayList<>();
-        final int TRANSACTION_SIZE = 1000;
-        double[] applyBatchTimes = MeasureTime.measure(TRANSACTION_RUNS, new MeasureRun() {
-            @Override
-            public void run(int i) {
-                operations.clear();
-                for (int j = 0; j < TRANSACTION_SIZE; ++j) {
-                    ContentValues values = new ContentValues();
-                    values.put(Channels.COLUMN_INPUT_ID, mInputId);
-                    values.put(Channels.COLUMN_SERVICE_TYPE,
-                            Channels.SERVICE_TYPE_AUDIO_VIDEO);
-                    values.put(Channels.COLUMN_TYPE, Channels.TYPE_OTHER);
-                    operations.add(
-                            ContentProviderOperation.newInsert(Channels.CONTENT_URI)
-                            .withValues(values).build());
-                }
-                try {
-                    mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
-                } catch (OperationApplicationException | RemoteException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        });
-        getReportLog().printArray("Elapsed time for insert: ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[0] = Stat.getAverage(applyBatchTimes);
-
-        // Update
-        final String[] projection = { Channels._ID };
-        try (final Cursor cursor = mContentResolver.query(Channels.CONTENT_URI,
-                projection, null, null, null)) {
-            applyBatchTimes = MeasureTime.measure(TRANSACTION_RUNS, new MeasureRun() {
-                @Override
-                public void run(int i) {
-                    operations.clear();
-                    for (int j = 0; j < TRANSACTION_SIZE && cursor.moveToNext(); ++j) {
-                        Uri channelUri = TvContract.buildChannelUri(cursor.getLong(0));
-                        String number = Integer.toString(i * TRANSACTION_SIZE + j);
-                        operations.add(
-                                ContentProviderOperation.newUpdate(channelUri)
-                                .withValue(Channels.COLUMN_DISPLAY_NUMBER, number)
-                                .build());
-                    }
-                    try {
-                        mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
-                    } catch (OperationApplicationException | RemoteException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            });
-        }
-        getReportLog().printArray("Elapsed time for update: ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[1] = Stat.getAverage(applyBatchTimes);
-
-        // Query channels
-        applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
-            @Override
-            public void run(int i) {
-                try (Cursor cursor = mContentResolver.query(Channels.CONTENT_URI, null, null,
-                        null, null)) {
-                    while (cursor.moveToNext()) {
-                        // Do nothing. Just iterate all the items.
-                    }
-                }
-            }
-        });
-        getReportLog().printArray("Elapsed time for query (channels): ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[2] = Stat.getAverage(applyBatchTimes);
-
-        // Query a channel
-        try (final Cursor cursor = mContentResolver.query(Channels.CONTENT_URI,
-                projection, null, null, null)) {
-            applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
-                @Override
-                public void run(int i) {
-                    assertTrue(cursor.moveToNext());
-                    try (Cursor c = mContentResolver.query(TvContract.buildChannelUri(
-                            cursor.getLong(0)), null, null, null, null)) {
-                        while (c.moveToNext()) {
-                            // Do nothing. Just iterate all the items.
-                        }
-                    }
-                }
-            });
-        }
-        getReportLog().printArray("Elapsed time for query (a channel): ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[3] = Stat.getAverage(applyBatchTimes);
-
-        // Delete
-        applyBatchTimes = MeasureTime.measure(1, new MeasureRun() {
-            @Override
-            public void run(int i) {
-                mContentResolver.delete(TvContract.buildChannelsUriForInput(mInputId), null, null);
-            }
-        });
-        getReportLog().printArray("Elapsed time for delete: ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[4] = Stat.getAverage(applyBatchTimes);
-
-        getReportLog().printArray("Average elapsed time for insert, update, query (channels), "
-                + "query (a channel), delete: ",
-                averages, ResultType.LOWER_BETTER, ResultUnit.MS);
-    }
-
-    @TimeoutReq(minutes = 12)
-    public void testPrograms() throws Exception {
-        if (!mHasTvInputFramework) return;
-        double[] averages = new double[7];
-
-        // Prepare (insert channels)
-        final ArrayList<ContentProviderOperation> operations = new ArrayList<>();
-        final int TRANSACTION_SIZE = 1000;
-        final int NUM_CHANNELS = 100;
-        final List<Uri> channelUris = new ArrayList<>();
-
-        operations.clear();
-        for (int i = 0; i < NUM_CHANNELS; ++i) {
-            ContentValues values = new ContentValues();
-            values.put(Channels.COLUMN_INPUT_ID, mInputId);
-            values.put(Channels.COLUMN_SERVICE_TYPE,
-                    Channels.SERVICE_TYPE_AUDIO_VIDEO);
-            values.put(Channels.COLUMN_TYPE, Channels.TYPE_OTHER);
-            operations.add(
-                    ContentProviderOperation.newInsert(Channels.CONTENT_URI)
-                    .withValues(values).build());
-        }
-        try {
-            ContentProviderResult[] results =
-                    mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
-            for (ContentProviderResult result : results) {
-                channelUris.add(result.uri);
-            }
-        } catch (OperationApplicationException | RemoteException e) {
-            throw new RuntimeException(e);
-        }
-
-        // Insert
-        double[] applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
-            @Override
-            public void run(int i) {
-                operations.clear();
-                Uri channelUri = channelUris.get(i);
-                long channelId = ContentUris.parseId(channelUri);
-                for (int j = 0; j < TRANSACTION_SIZE; ++j) {
-                    ContentValues values = new ContentValues();
-                    values.put(Programs.COLUMN_CHANNEL_ID, channelId);
-                    operations.add(
-                            ContentProviderOperation.newInsert(Programs.CONTENT_URI)
-                            .withValues(values).build());
-                }
-                try {
-                    mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
-                } catch (OperationApplicationException | RemoteException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        });
-        getReportLog().printArray("Elapsed time for insert: ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[0] = Stat.getAverage(applyBatchTimes);
-
-        // Update
-        final long PROGRAM_DURATION_MS = 60 * 1000;
-        final String[] projection = { Programs._ID };
-        applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
-            @Override
-            public void run(int i) {
-                Uri channelUri = channelUris.get(i);
-                operations.clear();
-                try (Cursor cursor = mContentResolver.query(
-                        TvContract.buildProgramsUriForChannel(channelUri),
-                        projection, null, null, null)) {
-                    long startTimeMs = 0;
-                    long endTimeMs = 0;
-                    while (cursor.moveToNext()) {
-                        Uri programUri = TvContract.buildProgramUri(cursor.getLong(0));
-                        endTimeMs += PROGRAM_DURATION_MS;
-                        operations.add(
-                                ContentProviderOperation.newUpdate(programUri)
-                                .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS, startTimeMs)
-                                .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS, endTimeMs)
-                                .build());
-                        startTimeMs = endTimeMs;
-                    }
-                }
-                try {
-                    mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
-                } catch (OperationApplicationException | RemoteException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        });
-        getReportLog().printArray("Elapsed time for update: ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[1] = Stat.getAverage(applyBatchTimes);
-
-        // Query programs
-        applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
-            @Override
-            public void run(int i) {
-                try (Cursor cursor = mContentResolver.query(Programs.CONTENT_URI, null, null,
-                        null, null)) {
-                    while (cursor.moveToNext()) {
-                        // Do nothing. Just iterate all the items.
-                    }
-                }
-            }
-        });
-        getReportLog().printArray("Elapsed time for query (programs): ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[2] = Stat.getAverage(applyBatchTimes);
-
-        // Query programs with selection
-        applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
-            @Override
-            public void run(int i) {
-                Uri channelUri = channelUris.get(i);
-                try (Cursor cursor = mContentResolver.query(
-                        TvContract.buildProgramsUriForChannel(
-                                channelUri, 0,
-                                PROGRAM_DURATION_MS * TRANSACTION_SIZE / 2),
-                        null, null, null, null)) {
-                    while (cursor.moveToNext()) {
-                        // Do nothing. Just iterate all the items.
-                    }
-                }
-            }
-        });
-        getReportLog().printArray("Elapsed time for query (programs with selection): ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[3] = Stat.getAverage(applyBatchTimes);
-
-        // Query a program
-        try (final Cursor cursor = mContentResolver.query(Programs.CONTENT_URI,
-                projection, null, null, null)) {
-            applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
-                @Override
-                public void run(int i) {
-                    assertTrue(cursor.moveToNext());
-                    try (Cursor c = mContentResolver.query(TvContract.buildProgramUri(
-                            cursor.getLong(0)), null, null, null, null)) {
-                        while (c.moveToNext()) {
-                            // Do nothing. Just iterate all the items.
-                        }
-                    }
-                }
-            });
-        }
-        getReportLog().printArray("Elapsed time for query (a program): ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[4] = Stat.getAverage(applyBatchTimes);
-
-        // Delete programs
-        applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
-            @Override
-            public void run(int i) {
-                Uri channelUri = channelUris.get(i);
-                mContentResolver.delete(
-                        TvContract.buildProgramsUriForChannel(
-                                channelUri,
-                                PROGRAM_DURATION_MS * TRANSACTION_SIZE / 2,
-                                PROGRAM_DURATION_MS * TRANSACTION_SIZE),
-                        null, null);
-            }
-        });
-        getReportLog().printArray("Elapsed time for delete programs: ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[5] = Stat.getAverage(applyBatchTimes);
-
-        // Delete channels
-        applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
-            @Override
-            public void run(int i) {
-                Uri channelUri = channelUris.get(i);
-                mContentResolver.delete(channelUri, null, null);
-            }
-        });
-        getReportLog().printArray("Elapsed time for delete channels: ",
-                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
-        averages[6] = Stat.getAverage(applyBatchTimes);
-
-        getReportLog().printArray("Average elapsed time for insert, update, query (programs), "
-                + "query (programs with selection), query (a channel), delete (channels), "
-                + "delete (programs): ",
-                averages, ResultType.LOWER_BETTER, ResultUnit.MS);
-    }
-}
diff --git a/suite/cts/deviceTests/ui/Android.mk b/suite/cts/deviceTests/ui/Android.mk
deleted file mode 100644
index ee52172..0000000
--- a/suite/cts/deviceTests/ui/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceUi
-
-LOCAL_SDK_VERSION := 16
-
-include $(BUILD_CTS_PACKAGE)
-
-
diff --git a/suite/cts/deviceTests/ui/AndroidManifest.xml b/suite/cts/deviceTests/ui/AndroidManifest.xml
deleted file mode 100644
index b41008e7..0000000
--- a/suite/cts/deviceTests/ui/AndroidManifest.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.ui" >
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-
-        <activity
-            android:name=".ScrollingActivity"
-            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-
-    <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:label="UI Latency measurement"
-        android:targetPackage="com.android.cts.ui" >
-        <meta-data
-            android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
-    </instrumentation>
-
-</manifest>
diff --git a/suite/cts/deviceTests/ui/src/com/android/cts/ui/ScrollingActivity.java b/suite/cts/deviceTests/ui/src/com/android/cts/ui/ScrollingActivity.java
deleted file mode 100644
index 2229e97..0000000
--- a/suite/cts/deviceTests/ui/src/com/android/cts/ui/ScrollingActivity.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.ui;
-
-import android.app.ListActivity;
-import android.os.Bundle;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Activity for measuring scrolling time of long list.
- */
-public class ScrollingActivity extends ListActivity implements OnScrollListener {
-    static final String TAG = "ScrollingActivity";
-    private static final String NUM_ELEMENTS_EXTRA = "num_elements";
-    private static final int NUM_ELEMENTS_DEFAULT = 10000;
-    private static final int SCROLL_TIME_IN_MS = 1;
-    private static final int WAIT_TIMEOUT_IN_SECS = 5 * 60;
-    private String[] mItems;
-    private CountDownLatch mLatchStop = null;
-    private int mTargetLoc;
-    private int mNumElements;
-
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        mNumElements = getIntent().getIntExtra(NUM_ELEMENTS_EXTRA, NUM_ELEMENTS_DEFAULT);
-        mItems = new String[mNumElements];
-        for (int i = 0; i < mNumElements; i++) {
-            mItems[i] = Integer.toString(i);
-        }
-        setListAdapter(new ArrayAdapter<String>(this,
-                android.R.layout.simple_list_item_1, mItems));
-        ListView view = getListView();
-        view.setOnScrollListener(this);
-    }
-
-    public boolean scrollToTop() {
-        return doScroll(0);
-    }
-    public boolean scrollToBottom() {
-        return doScroll(mNumElements - 1);
-    }
-
-    private boolean doScroll(final int loc) {
-        mLatchStop = new CountDownLatch(1);
-        mTargetLoc = loc;
-        final ListView view = getListView();
-        runOnUiThread( new Runnable() {
-            @Override
-            public void run() {
-                view.smoothScrollToPositionFromTop(loc, 0, SCROLL_TIME_IN_MS);
-            }
-        });
-        boolean result = false;
-        try {
-            result = mLatchStop.await(WAIT_TIMEOUT_IN_SECS, TimeUnit.SECONDS);
-        } catch (InterruptedException e) {
-            // ignore
-        }
-        mLatchStop = null;
-        return result;
-    }
-
-    @Override
-    public void onScrollStateChanged(AbsListView view, int scrollState) {
-
-    }
-
-    @Override
-    public void onScroll(AbsListView view, int firstVisibleItem,
-            int visibleItemCount, int totalItemCount) {
-        //Log.i(TAG, "onScroll " + firstVisibleItem + " " + visibleItemCount);
-        if ((mTargetLoc >= firstVisibleItem) &&
-                (mTargetLoc <= (firstVisibleItem + visibleItemCount))) {
-            if (mLatchStop != null) {
-                mLatchStop.countDown();
-            }
-        }
-    }
-}
diff --git a/suite/cts/deviceTests/ui/src/com/android/cts/ui/ScrollingTest.java b/suite/cts/deviceTests/ui/src/com/android/cts/ui/ScrollingTest.java
deleted file mode 100644
index b5b40e4..0000000
--- a/suite/cts/deviceTests/ui/src/com/android/cts/ui/ScrollingTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.ui;
-
-import com.android.cts.util.MeasureRun;
-import com.android.cts.util.MeasureTime;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import android.cts.util.CtsActivityInstrumentationTestCase2;
-import com.android.cts.util.Stat;
-import com.android.cts.util.TimeoutReq;
-
-import java.io.IOException;
-
-public class ScrollingTest extends CtsActivityInstrumentationTestCase2<ScrollingActivity> {
-    private ScrollingActivity mActivity;
-
-    public ScrollingTest() {
-        super(ScrollingActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        getInstrumentation().waitForIdleSync();
-        try {
-            runTestOnUiThread(new Runnable() {
-                public void run() {
-                }
-            });
-        } catch (Throwable e) {
-            e.printStackTrace();
-            fail();
-        }
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mActivity = null;
-        super.tearDown();
-    }
-
-    @TimeoutReq(minutes = 30)
-    public void testFullScrolling() throws Exception {
-        final int NUMBER_REPEAT = 10;
-        final ScrollingActivity activity = mActivity;
-        double[] results = MeasureTime.measure(NUMBER_REPEAT, new MeasureRun() {
-
-            @Override
-            public void run(int i) throws IOException {
-                assertTrue(activity.scrollToBottom());
-                assertTrue(activity.scrollToTop());
-            }
-        });
-        getReportLog().printArray("scrolling time", results, ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-        Stat.StatResult stat = Stat.getStat(results);
-        getReportLog().printSummary("scrolling time", stat.mAverage, ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-    }
-}
diff --git a/suite/cts/deviceTests/videoperf/Android.mk b/suite/cts/deviceTests/videoperf/Android.mk
deleted file mode 100644
index b589475..0000000
--- a/suite/cts/deviceTests/videoperf/Android.mk
+++ /dev/null
@@ -1,39 +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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil ctstestrunner
-
-LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceVideoPerf
-
-LOCAL_SDK_VERSION := current
-
-cts_runtime_hint := 50
-
-include $(BUILD_CTS_PACKAGE)
-
diff --git a/suite/cts/deviceTests/videoperf/AndroidManifest.xml b/suite/cts/deviceTests/videoperf/AndroidManifest.xml
deleted file mode 100644
index ca01298b..0000000
--- a/suite/cts/deviceTests/videoperf/AndroidManifest.xml
+++ /dev/null
@@ -1,33 +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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.videoperf">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.videoperf"
-            android:label="UI Latency measurement" >
-        <meta-data
-            android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
-    </instrumentation>
-</manifest>
diff --git a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/CodecInfo.java b/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/CodecInfo.java
deleted file mode 100644
index ccb3126..0000000
--- a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/CodecInfo.java
+++ /dev/null
@@ -1,108 +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.videoperf;
-
-import android.media.MediaCodec;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecInfo.CodecCapabilities;
-import android.media.MediaCodecInfo.CodecProfileLevel;
-import android.media.MediaCodecInfo.VideoCapabilities;
-import android.media.MediaCodecList;
-import android.media.MediaFormat;
-import android.util.Log;
-import android.util.Range;
-
-import java.io.IOException;
-
-/**
- * Utility class for getting codec information like bit rate, fps, and etc.
- * Uses public member variables instead of methods as this code is only for video benchmarking.
- */
-public class CodecInfo {
-    /** bit rate in bps */
-    public int mBitRate = 0;
-    /** Frame rate */
-    public int mFps = 0;
-    /** if codec is supporting YUV semiplanar format */
-    public boolean mSupportSemiPlanar = false;
-    /** if codec is supporting YUV planar format */
-    public boolean mSupportPlanar = false;
-
-    private static final String TAG = "CodecInfo";
-    private static final String VIDEO_AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
-    /**
-     * Check if given codec with given (w,h) is supported.
-     * @param codecName codec name
-     * @param mimeType codec type in mime format like MediaFormat.MIMETYPE_VIDEO_AVC
-     * @param w video width
-     * @param h video height
-     * @return null if the configuration is not supported.
-     */
-    public static CodecInfo getSupportedFormatInfo(
-            String codecName, String mimeType, int w, int h) {
-        MediaCodec codec;
-        try {
-            codec = MediaCodec.createByCodecName(codecName);
-        } catch (IOException e) {
-            return null;
-        }
-
-        CodecCapabilities cap = codec.getCodecInfo().getCapabilitiesForType(mimeType);
-        if (cap.colorFormats.length == 0) {
-            Log.w(TAG, "no supported color format");
-            codec.release();
-            return null;
-        }
-
-        CodecInfo info = new CodecInfo();
-        for (int color : cap.colorFormats) {
-            if (color == CodecCapabilities.COLOR_FormatYUV420SemiPlanar) {
-                info.mSupportSemiPlanar = true;
-            }
-            if (color == CodecCapabilities.COLOR_FormatYUV420Planar) {
-                info.mSupportPlanar = true;
-            }
-        }
-        printIntArray("supported colors", cap.colorFormats);
-
-        VideoCapabilities vidCap = cap.getVideoCapabilities();
-        try {
-            info.mFps = vidCap.getSupportedFrameRatesFor(w, h).getUpper().intValue();
-        } catch (IllegalArgumentException e) {
-            Log.w(TAG, "unsupported size");
-            codec.release();
-            return null;
-        }
-        info.mBitRate = vidCap.getBitrateRange().getUpper();
-        Log.i(TAG, "test bit rate " + info.mBitRate + " fps " + info.mFps);
-        codec.release();
-        return info;
-    }
-
-    // for debugging
-    private static void printIntArray(String msg, int[] data) {
-        StringBuilder builder = new StringBuilder();
-        builder.append(msg);
-        builder.append(":");
-        for (int e : data) {
-            builder.append(Integer.toHexString(e));
-            builder.append(",");
-        }
-        builder.deleteCharAt(builder.length() - 1);
-        Log.i(TAG, builder.toString());
-    }
-}
diff --git a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java b/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
deleted file mode 100644
index 62f37c5..0000000
--- a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
+++ /dev/null
@@ -1,1260 +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.videoperf;
-
-import android.cts.util.MediaUtils;
-import android.cts.util.DeviceReportLog;
-import android.graphics.ImageFormat;
-import android.graphics.Point;
-import android.media.cts.CodecImage;
-import android.media.cts.CodecUtils;
-import android.media.Image;
-import android.media.Image.Plane;
-import android.media.MediaCodec;
-import android.media.MediaCodec.BufferInfo;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecInfo.CodecCapabilities;
-import android.media.MediaCodecList;
-import android.media.MediaFormat;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Range;
-import android.util.Size;
-
-import android.cts.util.CtsAndroidTestCase;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.cts.util.Stat;
-import com.android.cts.util.TimeoutReq;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.lang.System;
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.Random;
-import java.util.Vector;
-
-/**
- * This tries to test video encoder / decoder performance by running encoding / decoding
- * without displaying the raw data. To make things simpler, encoder is used to encode synthetic
- * data and decoder is used to decode the encoded video. This approach does not work where
- * there is only decoder. Performance index is total time taken for encoding and decoding
- * the whole frames.
- * To prevent sacrificing quality for faster encoding / decoding, randomly selected pixels are
- * compared with the original image. As the pixel comparison can slow down the decoding process,
- * only some randomly selected pixels are compared. As there can be only one performance index,
- * error above certain threshold in pixel value will be treated as an error.
- */
-public class VideoEncoderDecoderTest extends CtsAndroidTestCase {
-    private static final String TAG = "VideoEncoderDecoderTest";
-    // this wait time affects fps as too big value will work as a blocker if device fps
-    // is not very high.
-    private static final long VIDEO_CODEC_WAIT_TIME_US = 5000;
-    private static final boolean VERBOSE = false;
-    private static final String VIDEO_AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
-    private static final String VIDEO_VP8 = MediaFormat.MIMETYPE_VIDEO_VP8;
-    private static final String VIDEO_H263 = MediaFormat.MIMETYPE_VIDEO_H263;
-    private static final String VIDEO_MPEG4 = MediaFormat.MIMETYPE_VIDEO_MPEG4;
-    private int mCurrentTestRound = 0;
-    private double[][] mEncoderFrameTimeDiff = null;
-    private double[][] mDecoderFrameTimeDiff = null;
-    // i frame interval for encoder
-    private static final int KEY_I_FRAME_INTERVAL = 5;
-    private static final int MOVING_AVERAGE_NUM = 10;
-
-    private static final int Y_CLAMP_MIN = 16;
-    private static final int Y_CLAMP_MAX = 235;
-    private static final int YUV_PLANE_ADDITIONAL_LENGTH = 200;
-    private ByteBuffer mYBuffer, mYDirectBuffer;
-    private ByteBuffer mUVBuffer, mUVDirectBuffer;
-    private int mSrcColorFormat;
-    private int mDstColorFormat;
-    private int mBufferWidth;
-    private int mBufferHeight;
-    private int mVideoWidth;
-    private int mVideoHeight;
-    private int mFrameRate;
-
-    private MediaFormat mEncInputFormat;
-    private MediaFormat mEncOutputFormat;
-    private MediaFormat mDecOutputFormat;
-
-    private LinkedList<Pair<ByteBuffer, BufferInfo>> mEncodedOutputBuffer;
-    // check this many pixels per each decoded frame
-    // checking too many points decreases decoder frame rates a lot.
-    private static final int PIXEL_CHECK_PER_FRAME = 1000;
-    // RMS error in pixel values above this will be treated as error.
-    private static final double PIXEL_RMS_ERROR_MARGAIN = 20.0;
-    private double mRmsErrorMargain = PIXEL_RMS_ERROR_MARGAIN;
-    private Random mRandom;
-
-    private class TestConfig {
-        public boolean mTestPixels = true;
-        public boolean mTestResult = false;
-        public boolean mReportFrameTime = false;
-        public int mTotalFrames = 300;
-        public int mMaxTimeMs = 120000;  // 2 minutes
-        public int mNumberOfRepeat = 10;
-    }
-
-    private TestConfig mTestConfig;
-
-    private DeviceReportLog mReportLog;
-
-    @Override
-    protected void setUp() throws Exception {
-        mEncodedOutputBuffer = new LinkedList<Pair<ByteBuffer, BufferInfo>>();
-        // Use time as a seed, hoping to prevent checking pixels in the same pattern
-        long now = System.currentTimeMillis();
-        mRandom = new Random(now);
-        mTestConfig = new TestConfig();
-        mReportLog = new DeviceReportLog();
-        super.setUp();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mEncodedOutputBuffer.clear();
-        mEncodedOutputBuffer = null;
-        mYBuffer = null;
-        mUVBuffer = null;
-        mYDirectBuffer = null;
-        mUVDirectBuffer = null;
-        mRandom = null;
-        mTestConfig = null;
-        mReportLog.deliverReportToHost(getInstrumentation());
-        super.tearDown();
-    }
-
-    private String getEncoderName(String mime) {
-        return getCodecName(mime, true /* isEncoder */);
-    }
-
-    private String getDecoderName(String mime) {
-        return getCodecName(mime, false /* isEncoder */);
-    }
-
-    private String getCodecName(String mime, boolean isEncoder) {
-        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-        for (MediaCodecInfo info : mcl.getCodecInfos()) {
-            if (info.isEncoder() != isEncoder) {
-                continue;
-            }
-            CodecCapabilities caps = null;
-            try {
-                caps = info.getCapabilitiesForType(mime);
-            } catch (IllegalArgumentException e) {  // mime is not supported
-                continue;
-            }
-            return info.getName();
-        }
-        return null;
-    }
-
-    private String[] getEncoderName(String mime, boolean isGoog) {
-        return getCodecName(mime, isGoog, true /* isEncoder */);
-    }
-
-    private String[] getDecoderName(String mime, boolean isGoog) {
-        return getCodecName(mime, isGoog, false /* isEncoder */);
-    }
-
-    private String[] getCodecName(String mime, boolean isGoog, boolean isEncoder) {
-        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-        ArrayList<String> result = new ArrayList<String>();
-        for (MediaCodecInfo info : mcl.getCodecInfos()) {
-            if (info.isEncoder() != isEncoder
-                    || info.getName().toLowerCase().startsWith("omx.google.") != isGoog) {
-                continue;
-            }
-            CodecCapabilities caps = null;
-            try {
-                caps = info.getCapabilitiesForType(mime);
-            } catch (IllegalArgumentException e) {  // mime is not supported
-                continue;
-            }
-            result.add(info.getName());
-        }
-        return result.toArray(new String[result.size()]);
-    }
-
-    public void testAvc0176x0144() throws Exception {
-        doTestDefault(VIDEO_AVC, 176, 144);
-    }
-
-    public void testAvc0352x0288() throws Exception {
-        doTestDefault(VIDEO_AVC, 352, 288);
-    }
-
-    public void testAvc0720x0480() throws Exception {
-        doTestDefault(VIDEO_AVC, 720, 480);
-    }
-
-    public void testAvc1280x0720() throws Exception {
-        doTestDefault(VIDEO_AVC, 1280, 720);
-    }
-
-    /**
-     * resolution intentionally set to 1072 not 1080
-     * as 1080 is not multiple of 16, and it requires additional setting like stride
-     * which is not specified in API documentation.
-     */
-    public void testAvc1920x1072() throws Exception {
-        doTestDefault(VIDEO_AVC, 1920, 1072);
-    }
-
-    // Avc tests
-    public void testAvc0320x0240Other() throws Exception {
-        doTestOther(VIDEO_AVC, 320, 240);
-    }
-
-    public void testAvc0320x0240Goog() throws Exception {
-        doTestGoog(VIDEO_AVC, 320, 240);
-    }
-
-    public void testAvc0720x0480Other() throws Exception {
-        doTestOther(VIDEO_AVC, 720, 480);
-    }
-
-    public void testAvc0720x0480Goog() throws Exception {
-        doTestGoog(VIDEO_AVC, 720, 480);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testAvc1280x0720Other() throws Exception {
-        doTestOther(VIDEO_AVC, 1280, 720);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testAvc1280x0720Goog() throws Exception {
-        doTestGoog(VIDEO_AVC, 1280, 720);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testAvc1920x1080Other() throws Exception {
-        doTestOther(VIDEO_AVC, 1920, 1080);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testAvc1920x1080Goog() throws Exception {
-        doTestGoog(VIDEO_AVC, 1920, 1080);
-    }
-
-    // Vp8 tests
-    public void testVp80320x0180Other() throws Exception {
-        doTestOther(VIDEO_VP8, 320, 180);
-    }
-
-    public void testVp80320x0180Goog() throws Exception {
-        doTestGoog(VIDEO_VP8, 320, 180);
-    }
-
-    public void testVp80640x0360Other() throws Exception {
-        doTestOther(VIDEO_VP8, 640, 360);
-    }
-
-    public void testVp80640x0360Goog() throws Exception {
-        doTestGoog(VIDEO_VP8, 640, 360);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testVp81280x0720Other() throws Exception {
-        doTestOther(VIDEO_VP8, 1280, 720);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testVp81280x0720Goog() throws Exception {
-        doTestGoog(VIDEO_VP8, 1280, 720);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testVp81920x1080Other() throws Exception {
-        doTestOther(VIDEO_VP8, 1920, 1080);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testVp81920x1080Goog() throws Exception {
-        doTestGoog(VIDEO_VP8, 1920, 1080);
-    }
-
-    // H263 tests
-    public void testH2630176x0144Other() throws Exception {
-        doTestOther(VIDEO_H263, 176, 144);
-    }
-
-    public void testH2630176x0144Goog() throws Exception {
-        doTestGoog(VIDEO_H263, 176, 144);
-    }
-
-    public void testH2630352x0288Other() throws Exception {
-        doTestOther(VIDEO_H263, 352, 288);
-    }
-
-    public void testH2630352x0288Goog() throws Exception {
-        doTestGoog(VIDEO_H263, 352, 288);
-    }
-
-    // Mpeg4 tests
-    public void testMpeg40176x0144Other() throws Exception {
-        doTestOther(VIDEO_MPEG4, 176, 144);
-    }
-
-    public void testMpeg40176x0144Goog() throws Exception {
-        doTestGoog(VIDEO_MPEG4, 176, 144);
-    }
-
-    public void testMpeg40352x0288Other() throws Exception {
-        doTestOther(VIDEO_MPEG4, 352, 288);
-    }
-
-    public void testMpeg40352x0288Goog() throws Exception {
-        doTestGoog(VIDEO_MPEG4, 352, 288);
-    }
-
-    public void testMpeg40640x0480Other() throws Exception {
-        doTestOther(VIDEO_MPEG4, 640, 480);
-    }
-
-    public void testMpeg40640x0480Goog() throws Exception {
-        doTestGoog(VIDEO_MPEG4, 640, 480);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testMpeg41280x0720Other() throws Exception {
-        doTestOther(VIDEO_MPEG4, 1280, 720);
-    }
-
-    @TimeoutReq(minutes = 10)
-    public void testMpeg41280x0720Goog() throws Exception {
-        doTestGoog(VIDEO_MPEG4, 1280, 720);
-    }
-
-    private boolean isSrcSemiPlanar() {
-        return mSrcColorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
-    }
-
-    private boolean isSrcFlexYUV() {
-        return mSrcColorFormat == CodecCapabilities.COLOR_FormatYUV420Flexible;
-    }
-
-    private boolean isDstSemiPlanar() {
-        return mDstColorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
-    }
-
-    private boolean isDstFlexYUV() {
-        return mDstColorFormat == CodecCapabilities.COLOR_FormatYUV420Flexible;
-    }
-
-    private static int getColorFormat(CodecInfo info) {
-        if (info.mSupportSemiPlanar) {
-            return CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
-        } else if (info.mSupportPlanar) {
-            return CodecCapabilities.COLOR_FormatYUV420Planar;
-        } else {
-            // FlexYUV must be supported
-            return CodecCapabilities.COLOR_FormatYUV420Flexible;
-        }
-    }
-
-    private void doTestGoog(String mimeType, int w, int h) throws Exception {
-        mTestConfig.mTestPixels = false;
-        mTestConfig.mTestResult = true;
-        mTestConfig.mTotalFrames = 3000;
-        mTestConfig.mNumberOfRepeat = 2;
-        doTest(true /* isGoog */, mimeType, w, h);
-    }
-
-    private void doTestOther(String mimeType, int w, int h) throws Exception {
-        mTestConfig.mTestPixels = false;
-        mTestConfig.mTestResult = true;
-        mTestConfig.mTotalFrames = 3000;
-        mTestConfig.mNumberOfRepeat = 2;
-        doTest(false /* isGoog */, mimeType, w, h);
-    }
-
-    private void doTestDefault(String mimeType, int w, int h) throws Exception {
-        String encoderName = getEncoderName(mimeType);
-        if (encoderName == null) {
-            Log.i(TAG, "Encoder for " + mimeType + " not found");
-            return;
-        }
-
-        String decoderName = getDecoderName(mimeType);
-        if (decoderName == null) {
-            Log.i(TAG, "Encoder for " + mimeType + " not found");
-            return;
-        }
-
-        doTestByName(encoderName, decoderName, mimeType, w, h);
-    }
-
-    /**
-     * Run encoding / decoding test for given mimeType of codec
-     * @param isGoog test google or non-google codec.
-     * @param mimeType like video/avc
-     * @param w video width
-     * @param h video height
-     */
-    private void doTest(boolean isGoog, String mimeType, int w, int h)
-            throws Exception {
-        String[] encoderNames = getEncoderName(mimeType, isGoog);
-        if (encoderNames.length == 0) {
-            Log.i(TAG, isGoog ? "Google " : "Non-google "
-                    + "encoder for " + mimeType + " not found");
-            return;
-        }
-
-        String[] decoderNames = getDecoderName(mimeType, isGoog);
-        if (decoderNames.length == 0) {
-            Log.i(TAG, isGoog ? "Google " : "Non-google "
-                    + "decoder for " + mimeType + " not found");
-            return;
-        }
-
-        for (String encoderName: encoderNames) {
-            for (String decoderName: decoderNames) {
-                doTestByName(encoderName, decoderName, mimeType, w, h);
-            }
-        }
-    }
-
-    private void doTestByName(
-            String encoderName, String decoderName, String mimeType, int w, int h)
-            throws Exception {
-        CodecInfo infoEnc = CodecInfo.getSupportedFormatInfo(encoderName, mimeType, w, h);
-        if (infoEnc == null) {
-            Log.i(TAG, "Encoder " + mimeType + " with " + w + "," + h + " not supported");
-            return;
-        }
-        CodecInfo infoDec = CodecInfo.getSupportedFormatInfo(decoderName, mimeType, w, h);
-        assertNotNull(infoDec);
-        mVideoWidth = w;
-        mVideoHeight = h;
-
-        mSrcColorFormat = getColorFormat(infoEnc);
-        mDstColorFormat = getColorFormat(infoDec);
-        Log.i(TAG, "Testing video resolution " + w + "x" + h +
-                   ": enc format " + mSrcColorFormat +
-                   ", dec format " + mDstColorFormat);
-
-        initYUVPlane(w + YUV_PLANE_ADDITIONAL_LENGTH, h + YUV_PLANE_ADDITIONAL_LENGTH);
-        mEncoderFrameTimeDiff =
-                new double[mTestConfig.mNumberOfRepeat][mTestConfig.mTotalFrames - 1];
-        mDecoderFrameTimeDiff =
-                new double[mTestConfig.mNumberOfRepeat][mTestConfig.mTotalFrames - 1];
-        double[] encoderFpsResults = new double[mTestConfig.mNumberOfRepeat];
-        double[] decoderFpsResults = new double[mTestConfig.mNumberOfRepeat];
-        double[] totalFpsResults = new double[mTestConfig.mNumberOfRepeat];
-        double[] decoderRmsErrorResults = new double[mTestConfig.mNumberOfRepeat];
-        boolean success = true;
-        for (int i = 0; i < mTestConfig.mNumberOfRepeat && success; i++) {
-            mCurrentTestRound = i;
-            MediaFormat format = new MediaFormat();
-            format.setString(MediaFormat.KEY_MIME, mimeType);
-            format.setInteger(MediaFormat.KEY_BIT_RATE, infoEnc.mBitRate);
-            format.setInteger(MediaFormat.KEY_WIDTH, w);
-            format.setInteger(MediaFormat.KEY_HEIGHT, h);
-            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mSrcColorFormat);
-            format.setInteger(MediaFormat.KEY_FRAME_RATE, infoEnc.mFps);
-            mFrameRate = infoEnc.mFps;
-            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, KEY_I_FRAME_INTERVAL);
-
-            double encodingTime = runEncoder(encoderName, format, mTestConfig.mTotalFrames);
-            // re-initialize format for decoder
-            format = new MediaFormat();
-            format.setString(MediaFormat.KEY_MIME, mimeType);
-            format.setInteger(MediaFormat.KEY_WIDTH, w);
-            format.setInteger(MediaFormat.KEY_HEIGHT, h);
-            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mDstColorFormat);
-            double[] decoderResult = runDecoder(decoderName, format);
-            if (decoderResult == null) {
-                success = false;
-            } else {
-                double decodingTime = decoderResult[0];
-                decoderRmsErrorResults[i] = decoderResult[1];
-                encoderFpsResults[i] = (double)mTestConfig.mTotalFrames / encodingTime * 1000.0;
-                decoderFpsResults[i] = (double)mTestConfig.mTotalFrames / decodingTime * 1000.0;
-                totalFpsResults[i] =
-                        (double)mTestConfig.mTotalFrames / (encodingTime + decodingTime) * 1000.0;
-            }
-
-            // clear things for re-start
-            mEncodedOutputBuffer.clear();
-            // it will be good to clean everything to make every run the same.
-            System.gc();
-        }
-        mReportLog.printArray("encoder", encoderFpsResults, ResultType.HIGHER_BETTER,
-                ResultUnit.FPS);
-        mReportLog.printArray("rms error", decoderRmsErrorResults, ResultType.LOWER_BETTER,
-                ResultUnit.NONE);
-        mReportLog.printArray("decoder", decoderFpsResults, ResultType.HIGHER_BETTER,
-                ResultUnit.FPS);
-        mReportLog.printArray("encoder decoder", totalFpsResults, ResultType.HIGHER_BETTER,
-                ResultUnit.FPS);
-        mReportLog.printValue(mimeType + " encoder average fps for " + w + "x" + h,
-                Stat.getAverage(encoderFpsResults), ResultType.HIGHER_BETTER, ResultUnit.FPS);
-        mReportLog.printValue(mimeType + " decoder average fps for " + w + "x" + h,
-                Stat.getAverage(decoderFpsResults), ResultType.HIGHER_BETTER, ResultUnit.FPS);
-        mReportLog.printSummary("encoder decoder", Stat.getAverage(totalFpsResults),
-                ResultType.HIGHER_BETTER, ResultUnit.FPS);
-
-        boolean encTestPassed = false;
-        boolean decTestPassed = false;
-        double[] measuredFps = new double[mTestConfig.mNumberOfRepeat];
-        String[] resultRawData = new String[mTestConfig.mNumberOfRepeat];
-        for (int i = 0; i < mTestConfig.mNumberOfRepeat; i++) {
-            // make sure that rms error is not too big.
-            if (decoderRmsErrorResults[i] >= mRmsErrorMargain) {
-                fail("rms error is bigger than the limit "
-                        + decoderRmsErrorResults[i] + " vs " + mRmsErrorMargain);
-            }
-
-            if (mTestConfig.mReportFrameTime) {
-                mReportLog.printValue(
-                        "encodertest#" + i + ": " + Arrays.toString(mEncoderFrameTimeDiff[i]),
-                        0, ResultType.NEUTRAL, ResultUnit.NONE);
-                mReportLog.printValue(
-                        "decodertest#" + i + ": " + Arrays.toString(mDecoderFrameTimeDiff[i]),
-                        0, ResultType.NEUTRAL, ResultUnit.NONE);
-            }
-
-            if (mTestConfig.mTestResult) {
-                double[] avgs = MediaUtils.calculateMovingAverage(
-                        mEncoderFrameTimeDiff[i], MOVING_AVERAGE_NUM);
-                double encMin = Stat.getMin(avgs);
-                double encMax = Stat.getMax(avgs);
-                double encAvg = MediaUtils.getAverage(mEncoderFrameTimeDiff[i]);
-                double encStdev = MediaUtils.getStdev(avgs);
-                String prefix = "codec=" + encoderName + " round=" + i +
-                        " EncInputFormat=" + mEncInputFormat +
-                        " EncOutputFormat=" + mEncOutputFormat;
-                String result =
-                        MediaUtils.logResults(mReportLog, prefix, encMin, encMax, encAvg, encStdev);
-                double measuredEncFps = 1000000000 / encMin;
-                resultRawData[i] = result;
-                measuredFps[i] = measuredEncFps;
-                if (!encTestPassed) {
-                    encTestPassed = MediaUtils.verifyResults(
-                            encoderName, mimeType, w, h, measuredEncFps);
-                }
-
-                avgs = MediaUtils.calculateMovingAverage(
-                        mDecoderFrameTimeDiff[i], MOVING_AVERAGE_NUM);
-                double decMin = Stat.getMin(avgs);
-                double decMax = Stat.getMax(avgs);
-                double decAvg = MediaUtils.getAverage(mDecoderFrameTimeDiff[i]);
-                double decStdev = MediaUtils.getStdev(avgs);
-                prefix = "codec=" + decoderName + " size=" + w + "x" + h + " round=" + i +
-                        " DecOutputFormat=" + mDecOutputFormat;
-                MediaUtils.logResults(mReportLog, prefix, decMin, decMax, decAvg, decStdev);
-                double measuredDecFps = 1000000000 / decMin;
-                if (!decTestPassed) {
-                    decTestPassed = MediaUtils.verifyResults(
-                            decoderName, mimeType, w, h, measuredDecFps);
-                }
-            }
-        }
-
-        if (mTestConfig.mTestResult) {
-            if (!encTestPassed) {
-                Range<Double> reportedRange =
-                    MediaUtils.getAchievableFrameRatesFor(encoderName, mimeType, w, h);
-                String failMessage =
-                    MediaUtils.getErrorMessage(reportedRange, measuredFps, resultRawData);
-                fail(failMessage);
-            }
-            // Decoder result will be verified in VideoDecoderPerfTest
-            // if (!decTestPassed) {
-            //     fail("Measured fps for " + decoderName +
-            //             " doesn't match with reported achievable frame rates.");
-            // }
-        }
-        measuredFps = null;
-        resultRawData = null;
-    }
-
-    /**
-     * run encoder benchmarking
-     * @param encoderName encoder name
-     * @param format format of media to encode
-     * @param totalFrames total number of frames to encode
-     * @return time taken in ms to encode the frames. This does not include initialization time.
-     */
-    private double runEncoder(String encoderName, MediaFormat format, int totalFrames) {
-        MediaCodec codec = null;
-        try {
-            codec = MediaCodec.createByCodecName(encoderName);
-            codec.configure(
-                    format,
-                    null /* surface */,
-                    null /* crypto */,
-                    MediaCodec.CONFIGURE_FLAG_ENCODE);
-        } catch (IllegalStateException e) {
-            Log.e(TAG, "codec '" + encoderName + "' failed configuration.");
-            codec.release();
-            assertTrue("codec '" + encoderName + "' failed configuration.", false);
-        } catch (IOException | NullPointerException e) {
-            Log.i(TAG, "could not find codec for " + format);
-            return Double.NaN;
-        }
-        codec.start();
-        mEncInputFormat = codec.getInputFormat();
-        ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
-
-        int numBytesSubmitted = 0;
-        int numBytesDequeued = 0;
-        int inFramesCount = 0;
-        long lastOutputTimeNs = 0;
-        long start = System.currentTimeMillis();
-        while (true) {
-            int index;
-
-            if (inFramesCount < totalFrames) {
-                index = codec.dequeueInputBuffer(VIDEO_CODEC_WAIT_TIME_US /* timeoutUs */);
-                if (index != MediaCodec.INFO_TRY_AGAIN_LATER) {
-                    int size;
-                    boolean eos = (inFramesCount == (totalFrames - 1));
-                    if (!eos && ((System.currentTimeMillis() - start) > mTestConfig.mMaxTimeMs)) {
-                        eos = true;
-                    }
-                    // when encoder only supports flexYUV, use Image only; otherwise,
-                    // use ByteBuffer & Image each on half of the frames to test both
-                    if (isSrcFlexYUV() || inFramesCount % 2 == 0) {
-                        Image image = codec.getInputImage(index);
-                        // image should always be available
-                        assertTrue(image != null);
-                        size = queueInputImageEncoder(
-                                codec, image, index, inFramesCount,
-                                eos ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
-                    } else {
-                        ByteBuffer buffer = codec.getInputBuffer(index);
-                        size = queueInputBufferEncoder(
-                                codec, buffer, index, inFramesCount,
-                                eos ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
-                    }
-                    inFramesCount++;
-                    numBytesSubmitted += size;
-                    if (VERBOSE) {
-                        Log.d(TAG, "queued " + size + " bytes of input data, frame " +
-                                (inFramesCount - 1));
-                    }
-
-                }
-            }
-            MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
-            index = codec.dequeueOutputBuffer(info, VIDEO_CODEC_WAIT_TIME_US /* timeoutUs */);
-            if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
-            } else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
-                mEncOutputFormat = codec.getOutputFormat();
-            } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
-                codecOutputBuffers = codec.getOutputBuffers();
-            } else if (index >= 0) {
-                if (lastOutputTimeNs > 0) {
-                    int pos = mEncodedOutputBuffer.size() - 1;
-                    if (pos < mEncoderFrameTimeDiff[mCurrentTestRound].length) {
-                        long diff = System.nanoTime() - lastOutputTimeNs;
-                        mEncoderFrameTimeDiff[mCurrentTestRound][pos] = diff;
-                    }
-                }
-                lastOutputTimeNs = System.nanoTime();
-
-                dequeueOutputBufferEncoder(codec, codecOutputBuffers, index, info);
-                numBytesDequeued += info.size;
-                if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-                    if (VERBOSE) {
-                        Log.d(TAG, "dequeued output EOS.");
-                    }
-                    break;
-                }
-                if (VERBOSE) {
-                    Log.d(TAG, "dequeued " + info.size + " bytes of output data.");
-                }
-            }
-        }
-        long finish = System.currentTimeMillis();
-        int validDataNum = Math.min(mEncodedOutputBuffer.size() - 1,
-                mEncoderFrameTimeDiff[mCurrentTestRound].length);
-        mEncoderFrameTimeDiff[mCurrentTestRound] =
-                Arrays.copyOf(mEncoderFrameTimeDiff[mCurrentTestRound], validDataNum);
-        if (VERBOSE) {
-            Log.d(TAG, "queued a total of " + numBytesSubmitted + "bytes, "
-                    + "dequeued " + numBytesDequeued + " bytes.");
-        }
-        codec.stop();
-        codec.release();
-        codec = null;
-        return (double)(finish - start);
-    }
-
-    /**
-     * Fills input buffer for encoder from YUV buffers.
-     * @return size of enqueued data.
-     */
-    private int queueInputBufferEncoder(
-            MediaCodec codec, ByteBuffer buffer, int index, int frameCount, int flags) {
-        buffer.clear();
-
-        Point origin = getOrigin(frameCount);
-        // Y color first
-        int srcOffsetY = origin.x + origin.y * mBufferWidth;
-        final byte[] yBuffer = mYBuffer.array();
-        for (int i = 0; i < mVideoHeight; i++) {
-            buffer.put(yBuffer, srcOffsetY, mVideoWidth);
-            srcOffsetY += mBufferWidth;
-        }
-        if (isSrcSemiPlanar()) {
-            int srcOffsetU = origin.y / 2 * mBufferWidth + origin.x / 2 * 2;
-            final byte[] uvBuffer = mUVBuffer.array();
-            for (int i = 0; i < mVideoHeight / 2; i++) {
-                buffer.put(uvBuffer, srcOffsetU, mVideoWidth);
-                srcOffsetU += mBufferWidth;
-            }
-        } else {
-            int srcOffsetU = origin.y / 2 * mBufferWidth / 2 + origin.x / 2;
-            int srcOffsetV = srcOffsetU + mBufferWidth / 2 * mBufferHeight / 2;
-            final byte[] uvBuffer = mUVBuffer.array();
-            for (int i = 0; i < mVideoHeight / 2; i++) { //U only
-                buffer.put(uvBuffer, srcOffsetU, mVideoWidth / 2);
-                srcOffsetU += mBufferWidth / 2;
-            }
-            for (int i = 0; i < mVideoHeight / 2; i++) { //V only
-                buffer.put(uvBuffer, srcOffsetV, mVideoWidth / 2);
-                srcOffsetV += mBufferWidth / 2;
-            }
-        }
-        int size = mVideoHeight * mVideoWidth * 3 / 2;
-        long ptsUsec = computePresentationTime(frameCount);
-
-        codec.queueInputBuffer(index, 0 /* offset */, size, ptsUsec /* timeUs */, flags);
-        if (VERBOSE && (frameCount == 0)) {
-            printByteArray("Y ", mYBuffer.array(), 0, 20);
-            printByteArray("UV ", mUVBuffer.array(), 0, 20);
-            printByteArray("UV ", mUVBuffer.array(), mBufferWidth * 60, 20);
-        }
-        return size;
-    }
-
-    class YUVImage extends CodecImage {
-        private final int mImageWidth;
-        private final int mImageHeight;
-        private final Plane[] mPlanes;
-
-        YUVImage(
-                Point origin,
-                int imageWidth, int imageHeight,
-                int arrayWidth, int arrayHeight,
-                boolean semiPlanar,
-                ByteBuffer bufferY, ByteBuffer bufferUV) {
-            mImageWidth = imageWidth;
-            mImageHeight = imageHeight;
-            ByteBuffer dupY = bufferY.duplicate();
-            ByteBuffer dupUV = bufferUV.duplicate();
-            mPlanes = new Plane[3];
-
-            int srcOffsetY = origin.x + origin.y * arrayWidth;
-
-            mPlanes[0] = new YUVPlane(
-                        mImageWidth, mImageHeight, arrayWidth, 1,
-                        dupY, srcOffsetY);
-
-            if (semiPlanar) {
-                int srcOffsetUV = origin.y / 2 * arrayWidth + origin.x / 2 * 2;
-
-                mPlanes[1] = new YUVPlane(
-                        mImageWidth / 2, mImageHeight / 2, arrayWidth, 2,
-                        dupUV, srcOffsetUV);
-                mPlanes[2] = new YUVPlane(
-                        mImageWidth / 2, mImageHeight / 2, arrayWidth, 2,
-                        dupUV, srcOffsetUV + 1);
-            } else {
-                int srcOffsetU = origin.y / 2 * arrayWidth / 2 + origin.x / 2;
-                int srcOffsetV = srcOffsetU + arrayWidth / 2 * arrayHeight / 2;
-
-                mPlanes[1] = new YUVPlane(
-                        mImageWidth / 2, mImageHeight / 2, arrayWidth / 2, 1,
-                        dupUV, srcOffsetU);
-                mPlanes[2] = new YUVPlane(
-                        mImageWidth / 2, mImageHeight / 2, arrayWidth / 2, 1,
-                        dupUV, srcOffsetV);
-            }
-        }
-
-        @Override
-        public int getFormat() {
-            return ImageFormat.YUV_420_888;
-        }
-
-        @Override
-        public int getWidth() {
-            return mImageWidth;
-        }
-
-        @Override
-        public int getHeight() {
-            return mImageHeight;
-        }
-
-        @Override
-        public long getTimestamp() {
-            return 0;
-        }
-
-        @Override
-        public Plane[] getPlanes() {
-            return mPlanes;
-        }
-
-        @Override
-        public void close() {
-            mPlanes[0] = null;
-            mPlanes[1] = null;
-            mPlanes[2] = null;
-        }
-
-        class YUVPlane extends CodecImage.Plane {
-            private final int mRowStride;
-            private final int mPixelStride;
-            private final ByteBuffer mByteBuffer;
-
-            YUVPlane(int w, int h, int rowStride, int pixelStride,
-                    ByteBuffer buffer, int offset) {
-                mRowStride = rowStride;
-                mPixelStride = pixelStride;
-
-                // only safe to access length bytes starting from buffer[offset]
-                int length = (h - 1) * rowStride + (w - 1) * pixelStride + 1;
-
-                buffer.position(offset);
-                mByteBuffer = buffer.slice();
-                mByteBuffer.limit(length);
-            }
-
-            @Override
-            public int getRowStride() {
-                return mRowStride;
-            }
-
-            @Override
-            public int getPixelStride() {
-                return mPixelStride;
-            }
-
-            @Override
-            public ByteBuffer getBuffer() {
-                return mByteBuffer;
-            }
-        }
-    }
-
-    /**
-     * Fills input image for encoder from YUV buffers.
-     * @return size of enqueued data.
-     */
-    private int queueInputImageEncoder(
-            MediaCodec codec, Image image, int index, int frameCount, int flags) {
-        assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
-
-
-        Point origin = getOrigin(frameCount);
-
-        // Y color first
-        CodecImage srcImage = new YUVImage(
-                origin,
-                mVideoWidth, mVideoHeight,
-                mBufferWidth, mBufferHeight,
-                isSrcSemiPlanar(),
-                mYDirectBuffer, mUVDirectBuffer);
-
-        CodecUtils.copyFlexYUVImage(image, srcImage);
-
-        int size = mVideoHeight * mVideoWidth * 3 / 2;
-        long ptsUsec = computePresentationTime(frameCount);
-
-        codec.queueInputBuffer(index, 0 /* offset */, size, ptsUsec /* timeUs */, flags);
-        if (VERBOSE && (frameCount == 0)) {
-            printByteArray("Y ", mYBuffer.array(), 0, 20);
-            printByteArray("UV ", mUVBuffer.array(), 0, 20);
-            printByteArray("UV ", mUVBuffer.array(), mBufferWidth * 60, 20);
-        }
-        return size;
-    }
-
-    /**
-     * Dequeue encoded data from output buffer and store for later usage.
-     */
-    private void dequeueOutputBufferEncoder(
-            MediaCodec codec, ByteBuffer[] outputBuffers,
-            int index, MediaCodec.BufferInfo info) {
-        ByteBuffer output = outputBuffers[index];
-        int l = info.size;
-        ByteBuffer copied = ByteBuffer.allocate(l);
-        output.get(copied.array(), 0, l);
-        BufferInfo savedInfo = new BufferInfo();
-        savedInfo.set(0, l, info.presentationTimeUs, info.flags);
-        mEncodedOutputBuffer.addLast(Pair.create(copied, savedInfo));
-        codec.releaseOutputBuffer(index, false /* render */);
-    }
-
-    /**
-     * run encoder benchmarking with encoded stream stored from encoding phase
-     * @param decoderName decoder name
-     * @param format format of media to decode
-     * @return returns length-2 array with 0: time for decoding, 1 : rms error of pixels
-     */
-    private double[] runDecoder(String decoderName, MediaFormat format) {
-        MediaCodec codec = null;
-        try {
-            codec = MediaCodec.createByCodecName(decoderName);
-        } catch (IOException | NullPointerException e) {
-            Log.i(TAG, "could not find decoder for " + format);
-            return null;
-        }
-        codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
-        codec.start();
-        ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
-
-        double totalErrorSquared = 0;
-
-        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
-        boolean sawOutputEOS = false;
-        int inputLeft = mEncodedOutputBuffer.size();
-        int inputBufferCount = 0;
-        int outFrameCount = 0;
-        YUVValue expected = new YUVValue();
-        YUVValue decoded = new YUVValue();
-        long lastOutputTimeNs = 0;
-        long start = System.currentTimeMillis();
-        while (!sawOutputEOS) {
-            if (inputLeft > 0) {
-                int inputBufIndex = codec.dequeueInputBuffer(VIDEO_CODEC_WAIT_TIME_US);
-
-                if (inputBufIndex >= 0) {
-                    ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
-                    dstBuf.clear();
-                    ByteBuffer src = mEncodedOutputBuffer.get(inputBufferCount).first;
-                    BufferInfo srcInfo = mEncodedOutputBuffer.get(inputBufferCount).second;
-                    int writeSize = src.capacity();
-                    dstBuf.put(src.array(), 0, writeSize);
-
-                    int flags = srcInfo.flags;
-                    if ((System.currentTimeMillis() - start) > mTestConfig.mMaxTimeMs) {
-                        flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
-                    }
-
-                    codec.queueInputBuffer(
-                            inputBufIndex,
-                            0 /* offset */,
-                            writeSize,
-                            srcInfo.presentationTimeUs,
-                            flags);
-                    inputLeft --;
-                    inputBufferCount ++;
-                }
-            }
-
-            int res = codec.dequeueOutputBuffer(info, VIDEO_CODEC_WAIT_TIME_US);
-            if (res >= 0) {
-                int outputBufIndex = res;
-
-                // only do YUV compare on EOS frame if the buffer size is none-zero
-                if (info.size > 0) {
-                    if (lastOutputTimeNs > 0) {
-                        int pos = outFrameCount - 1;
-                        if (pos < mDecoderFrameTimeDiff[mCurrentTestRound].length) {
-                            long diff = System.nanoTime() - lastOutputTimeNs;
-                            mDecoderFrameTimeDiff[mCurrentTestRound][pos] = diff;
-                        }
-                    }
-                    lastOutputTimeNs = System.nanoTime();
-
-                    if (mTestConfig.mTestPixels) {
-                        Point origin = getOrigin(outFrameCount);
-                        int i;
-
-                        // if decoder supports planar or semiplanar, check output with
-                        // ByteBuffer & Image each on half of the points
-                        int pixelCheckPerFrame = PIXEL_CHECK_PER_FRAME;
-                        if (!isDstFlexYUV()) {
-                            pixelCheckPerFrame /= 2;
-                            ByteBuffer buf = codec.getOutputBuffer(outputBufIndex);
-                            if (VERBOSE && (outFrameCount == 0)) {
-                                printByteBuffer("Y ", buf, 0, 20);
-                                printByteBuffer("UV ", buf, mVideoWidth * mVideoHeight, 20);
-                                printByteBuffer("UV ", buf,
-                                        mVideoWidth * mVideoHeight + mVideoWidth * 60, 20);
-                            }
-                            for (i = 0; i < pixelCheckPerFrame; i++) {
-                                int w = mRandom.nextInt(mVideoWidth);
-                                int h = mRandom.nextInt(mVideoHeight);
-                                getPixelValuesFromYUVBuffers(origin.x, origin.y, w, h, expected);
-                                getPixelValuesFromOutputBuffer(buf, w, h, decoded);
-                                if (VERBOSE) {
-                                    Log.i(TAG, outFrameCount + "-" + i + "- th round: ByteBuffer:"
-                                            + " expected "
-                                            + expected.mY + "," + expected.mU + "," + expected.mV
-                                            + " decoded "
-                                            + decoded.mY + "," + decoded.mU + "," + decoded.mV);
-                                }
-                                totalErrorSquared += expected.calcErrorSquared(decoded);
-                            }
-                        }
-
-                        Image image = codec.getOutputImage(outputBufIndex);
-                        assertTrue(image != null);
-                        for (i = 0; i < pixelCheckPerFrame; i++) {
-                            int w = mRandom.nextInt(mVideoWidth);
-                            int h = mRandom.nextInt(mVideoHeight);
-                            getPixelValuesFromYUVBuffers(origin.x, origin.y, w, h, expected);
-                            getPixelValuesFromImage(image, w, h, decoded);
-                            if (VERBOSE) {
-                                Log.i(TAG, outFrameCount + "-" + i + "- th round: FlexYUV:"
-                                        + " expcted "
-                                        + expected.mY + "," + expected.mU + "," + expected.mV
-                                        + " decoded "
-                                        + decoded.mY + "," + decoded.mU + "," + decoded.mV);
-                            }
-                            totalErrorSquared += expected.calcErrorSquared(decoded);
-                        }
-                    }
-                    outFrameCount++;
-                }
-                codec.releaseOutputBuffer(outputBufIndex, false /* render */);
-                if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-                    Log.d(TAG, "saw output EOS.");
-                    sawOutputEOS = true;
-                }
-            } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
-                mDecOutputFormat = codec.getOutputFormat();
-                Log.d(TAG, "output format has changed to " + mDecOutputFormat);
-                int colorFormat = mDecOutputFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
-                if (colorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar
-                        || colorFormat == CodecCapabilities.COLOR_FormatYUV420Planar) {
-                    mDstColorFormat = colorFormat;
-                } else {
-                    mDstColorFormat = CodecCapabilities.COLOR_FormatYUV420Flexible;
-                    Log.w(TAG, "output format changed to unsupported one " +
-                            Integer.toHexString(colorFormat) + ", using FlexYUV");
-                }
-            }
-        }
-        long finish = System.currentTimeMillis();
-        int validDataNum = Math.min(outFrameCount - 1,
-                mDecoderFrameTimeDiff[mCurrentTestRound].length);
-        mDecoderFrameTimeDiff[mCurrentTestRound] =
-                Arrays.copyOf(mDecoderFrameTimeDiff[mCurrentTestRound], validDataNum);
-        codec.stop();
-        codec.release();
-        codec = null;
-
-        // divide by 3 as sum is done for Y, U, V.
-        double errorRms = Math.sqrt(totalErrorSquared / PIXEL_CHECK_PER_FRAME / outFrameCount / 3);
-        double[] result = { (double) finish - start, errorRms };
-        return result;
-    }
-
-    /**
-     *  returns origin in the absolute frame for given frame count.
-     *  The video scene is moving by moving origin per each frame.
-     */
-    private Point getOrigin(int frameCount) {
-        if (frameCount < 100) {
-            return new Point(2 * frameCount, 0);
-        } else if (frameCount < 200) {
-            return new Point(200, (frameCount - 100) * 2);
-        } else {
-            if (frameCount > 300) { // for safety
-                frameCount = 300;
-            }
-            return new Point(600 - frameCount * 2, 600 - frameCount * 2);
-        }
-    }
-
-    /**
-     * initialize reference YUV plane
-     * @param w This should be YUV_PLANE_ADDITIONAL_LENGTH pixels bigger than video resolution
-     *          to allow movements
-     * @param h This should be YUV_PLANE_ADDITIONAL_LENGTH pixels bigger than video resolution
-     *          to allow movements
-     * @param semiPlanarEnc
-     * @param semiPlanarDec
-     */
-    private void initYUVPlane(int w, int h) {
-        int bufferSizeY = w * h;
-        mYBuffer = ByteBuffer.allocate(bufferSizeY);
-        mUVBuffer = ByteBuffer.allocate(bufferSizeY / 2);
-        mYDirectBuffer = ByteBuffer.allocateDirect(bufferSizeY);
-        mUVDirectBuffer = ByteBuffer.allocateDirect(bufferSizeY / 2);
-        mBufferWidth = w;
-        mBufferHeight = h;
-        final byte[] yArray = mYBuffer.array();
-        final byte[] uvArray = mUVBuffer.array();
-        for (int i = 0; i < h; i++) {
-            for (int j = 0; j < w; j++) {
-                yArray[i * w + j]  = clampY((i + j) & 0xff);
-            }
-        }
-        if (isSrcSemiPlanar()) {
-            for (int i = 0; i < h/2; i++) {
-                for (int j = 0; j < w/2; j++) {
-                    uvArray[i * w + 2 * j]  = (byte) (i & 0xff);
-                    uvArray[i * w + 2 * j + 1]  = (byte) (j & 0xff);
-                }
-            }
-        } else { // planar, U first, then V
-            int vOffset = bufferSizeY / 4;
-            for (int i = 0; i < h/2; i++) {
-                for (int j = 0; j < w/2; j++) {
-                    uvArray[i * w/2 + j]  = (byte) (i & 0xff);
-                    uvArray[i * w/2 + vOffset + j]  = (byte) (j & 0xff);
-                }
-            }
-        }
-        mYDirectBuffer.put(yArray);
-        mUVDirectBuffer.put(uvArray);
-        mYDirectBuffer.rewind();
-        mUVDirectBuffer.rewind();
-    }
-
-    /**
-     * class to store pixel values in YUV
-     *
-     */
-    public class YUVValue {
-        public byte mY;
-        public byte mU;
-        public byte mV;
-        public YUVValue() {
-        }
-
-        public boolean equalTo(YUVValue other) {
-            return (mY == other.mY) && (mU == other.mU) && (mV == other.mV);
-        }
-
-        public double calcErrorSquared(YUVValue other) {
-            double yDelta = mY - other.mY;
-            double uDelta = mU - other.mU;
-            double vDelta = mV - other.mV;
-            return yDelta * yDelta + uDelta * uDelta + vDelta * vDelta;
-        }
-    }
-
-    /**
-     * Read YUV values from given position (x,y) for given origin (originX, originY)
-     * The whole data is already available from YBuffer and UVBuffer.
-     * @param result pass the result via this. This is for avoiding creating / destroying too many
-     *               instances
-     */
-    private void getPixelValuesFromYUVBuffers(int originX, int originY, int x, int y,
-            YUVValue result) {
-        result.mY = mYBuffer.get((originY + y) * mBufferWidth + (originX + x));
-        if (isSrcSemiPlanar()) {
-            int index = (originY + y) / 2 * mBufferWidth + (originX + x) / 2 * 2;
-            //Log.d(TAG, "YUV " + originX + "," + originY + "," + x + "," + y + "," + index);
-            result.mU = mUVBuffer.get(index);
-            result.mV = mUVBuffer.get(index + 1);
-        } else {
-            int vOffset = mBufferWidth * mBufferHeight / 4;
-            int index = (originY + y) / 2 * mBufferWidth / 2 + (originX + x) / 2;
-            result.mU = mUVBuffer.get(index);
-            result.mV = mUVBuffer.get(vOffset + index);
-        }
-    }
-
-    /**
-     * Read YUV pixels from decoded output buffer for give (x, y) position
-     * Output buffer is composed of Y parts followed by U/V
-     * @param result pass the result via this. This is for avoiding creating / destroying too many
-     *               instances
-     */
-    private void getPixelValuesFromOutputBuffer(ByteBuffer buffer, int x, int y, YUVValue result) {
-        result.mY = buffer.get(y * mVideoWidth + x);
-        if (isDstSemiPlanar()) {
-            int index = mVideoWidth * mVideoHeight + y / 2 * mVideoWidth + x / 2 * 2;
-            //Log.d(TAG, "Decoded " + x + "," + y + "," + index);
-            result.mU = buffer.get(index);
-            result.mV = buffer.get(index + 1);
-        } else {
-            int vOffset = mVideoWidth * mVideoHeight / 4;
-            int index = mVideoWidth * mVideoHeight + y / 2 * mVideoWidth / 2 + x / 2;
-            result.mU = buffer.get(index);
-            result.mV = buffer.get(index + vOffset);
-        }
-    }
-
-    private void getPixelValuesFromImage(Image image, int x, int y, YUVValue result) {
-        assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
-
-        Plane[] planes = image.getPlanes();
-        assertTrue(planes.length == 3);
-
-        result.mY = getPixelFromPlane(planes[0], x, y);
-        result.mU = getPixelFromPlane(planes[1], x / 2, y / 2);
-        result.mV = getPixelFromPlane(planes[2], x / 2, y / 2);
-    }
-
-    private byte getPixelFromPlane(Plane plane, int x, int y) {
-        ByteBuffer buf = plane.getBuffer();
-        return buf.get(y * plane.getRowStride() + x * plane.getPixelStride());
-    }
-
-    /**
-     * Y cannot have full range. clamp it to prevent invalid value.
-     */
-    private byte clampY(int y) {
-        if (y < Y_CLAMP_MIN) {
-            y = Y_CLAMP_MIN;
-        } else if (y > Y_CLAMP_MAX) {
-            y = Y_CLAMP_MAX;
-        }
-        return (byte) (y & 0xff);
-    }
-
-    // for debugging
-    private void printByteArray(String msg, byte[] data, int offset, int len) {
-        StringBuilder builder = new StringBuilder();
-        builder.append(msg);
-        builder.append(":");
-        for (int i = offset; i < offset + len; i++) {
-            builder.append(Integer.toHexString(data[i]));
-            builder.append(",");
-        }
-        builder.deleteCharAt(builder.length() - 1);
-        Log.i(TAG, builder.toString());
-    }
-
-    // for debugging
-    private void printByteBuffer(String msg, ByteBuffer data, int offset, int len) {
-        StringBuilder builder = new StringBuilder();
-        builder.append(msg);
-        builder.append(":");
-        for (int i = offset; i < offset + len; i++) {
-            builder.append(Integer.toHexString(data.get(i)));
-            builder.append(",");
-        }
-        builder.deleteCharAt(builder.length() - 1);
-        Log.i(TAG, builder.toString());
-    }
-
-    /**
-     * Generates the presentation time for frame N, in microseconds.
-     */
-    private long computePresentationTime(int frameIndex) {
-        return 132 + frameIndex * 1000000L / mFrameRate;
-    }
-}
diff --git a/suite/cts/hostTests/Android.mk b/suite/cts/hostTests/Android.mk
deleted file mode 100644
index c141484..0000000
--- a/suite/cts/hostTests/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# 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.
-#
-
-include $(call all-subdir-makefiles)
diff --git a/suite/cts/hostTests/jank/Android.mk b/suite/cts/hostTests/jank/Android.mk
deleted file mode 100644
index 8f1be07..0000000
--- a/suite/cts/hostTests/jank/Android.mk
+++ /dev/null
@@ -1,43 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE := CtsHostJank
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_CTS_TEST_PACKAGE := com.android.cts.jank
-
-LOCAL_DEVICE_JAR_ := CtsDeviceJank
-cts_library_jar_ := $(CTS_TESTCASES_OUT)/$(LOCAL_DEVICE_JAR_).jar
-
-$(cts_library_jar_): $(call intermediates-dir-for,JAVA_LIBRARIES,$(LOCAL_DEVICE_JAR_))/javalib.jar | $(ACP)
-	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
-	$(hide) $(ACP) -fp $< $@
-
-$(CTS_TESTCASES_OUT)/CtsHostJank.xml: $(cts_library_jar_)
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-# Build the library using its own makefile
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/suite/cts/hostTests/jank/app/Android.mk b/suite/cts/hostTests/jank/app/Android.mk
deleted file mode 100644
index 8f4fce6..0000000
--- a/suite/cts/hostTests/jank/app/Android.mk
+++ /dev/null
@@ -1,28 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := CtsDeviceJank
-LOCAL_DEX_PREOPT := false
-
-LOCAL_JAVA_LIBRARIES := uiautomator.core
-
-LOCAL_STATIC_JAVA_LIBRARIES := com.android.uiautomator.platform.common
-
-include $(BUILD_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/suite/cts/hostTests/jank/app/src/com/android/cts/jank/CtsJankTestBase.java b/suite/cts/hostTests/jank/app/src/com/android/cts/jank/CtsJankTestBase.java
deleted file mode 100644
index 6d5162b..0000000
--- a/suite/cts/hostTests/jank/app/src/com/android/cts/jank/CtsJankTestBase.java
+++ /dev/null
@@ -1,97 +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.jank;
-
-import android.os.Bundle;
-import android.util.Log;
-
-import com.android.uiautomator.platform.JankTestBase;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Scanner;
-
-public class CtsJankTestBase extends JankTestBase {
-    private final static String TAG = CtsJankTestBase.class.getName();
-    protected final static String START_CMD = "am start -W -a android.intent.action.MAIN -n %s";
-    protected final static String STOP_CMD = "am force-stop %s";
-    protected final static String INTENT_STRING_EXTRA = " --es %s %s";
-    protected final static String INTENT_BOOLEAN_EXTRA = " --ez %s %b";
-    protected final static String INTENT_INTEGER_EXTRA = " --ei %s %d";
-    protected static long SLEEP_TIME = 2000; // 2 seconds
-    protected static int NUM_ITERATIONS = 5;
-    protected static int TRACE_TIME = 5;
-
-    @Override
-    protected String getPropertyString(Bundle params, String key)
-            throws FileNotFoundException, IOException {
-        if (key.equals("iteration")) {
-            return NUM_ITERATIONS + "";
-        }
-        if (key.equals("tracetime")) {
-            return TRACE_TIME + "";
-        }
-        return super.getPropertyString(params, key);
-    }
-
-    protected void runShellCommand(String command) throws Exception {
-        Process p = null;
-        Scanner out = null;
-        Scanner err = null;
-        try {
-            p = Runtime.getRuntime().exec(command);
-
-            StringBuilder outStr = new StringBuilder();
-            StringBuilder errStr = new StringBuilder();
-            out = new Scanner(p.getInputStream());
-            err = new Scanner(p.getErrorStream());
-            boolean read = true;
-            while (read) {
-                if (out.hasNextLine()) {
-                    outStr.append(out.nextLine());
-                    outStr.append("\n");
-                } else if (err.hasNextLine()) {
-                    errStr.append(err.nextLine());
-                    errStr.append("\n");
-                } else {
-                    read = false;
-                }
-            }
-            Log.i(TAG, command);
-            if (outStr.length() > 0) {
-                Log.i(TAG, outStr.toString());
-            }
-            if (errStr.length() > 0) {
-                Log.e(TAG, errStr.toString());
-            }
-        } finally {
-            if (p != null) {
-                int status = p.waitFor();
-                if (status != 0) {
-                    throw new RuntimeException(
-                            String.format("Run shell command: %s, status: %s", command, status));
-                }
-                p.destroy();
-                p = null;
-            }
-            if (out != null) {
-                out.close();
-            }
-            if (err != null) {
-                err.close();
-            }
-        }
-    }
-}
diff --git a/suite/cts/hostTests/jank/app/src/com/android/cts/jank/opengl/CtsDeviceJankOpenGl.java b/suite/cts/hostTests/jank/app/src/com/android/cts/jank/opengl/CtsDeviceJankOpenGl.java
deleted file mode 100755
index 5ba0613..0000000
--- a/suite/cts/hostTests/jank/app/src/com/android/cts/jank/opengl/CtsDeviceJankOpenGl.java
+++ /dev/null
@@ -1,111 +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.jank.opengl;
-
-import android.util.Log;
-
-import com.android.cts.jank.CtsJankTestBase;
-import com.android.uiautomator.platform.SurfaceFlingerHelper;
-
-public class CtsDeviceJankOpenGl extends CtsJankTestBase {
-    private final static String TAG = CtsDeviceJankOpenGl.class.getName();
-    private final static String PACKAGE = "com.android.cts.opengl";
-    private final static String COMPONENT =
-            PACKAGE + "/" + PACKAGE + ".primitive.GLPrimitiveActivity";
-    private static String APP_WINDOW_NAME = "SurfaceView";
-
-    /**
-     * Runs the full OpenGL ES 2.0 pipeline test.
-     */
-    public void testFullPipeline() throws Exception {
-        runBenchmark("FullPipeline");
-    }
-
-    /**
-     * Runs the pixel output test.
-     */
-    public void testPixelOutput() throws Exception {
-        runBenchmark("PixelOutput");
-    }
-
-    /**
-     * Runs the shader performance test.
-     */
-    public void testShaderPerf() throws Exception {
-        runBenchmark("ShaderPerf");
-    }
-
-    /**
-     * Runs the context switch overhead test.
-     */
-    public void testContextSwitch() throws Exception {
-        runBenchmark("ContextSwitch");
-    }
-
-    /**
-     * Runs the benchhmark for jank test.
-     */
-    public void runBenchmark(String benchmark) throws Exception {
-        // Start activity command
-        final StringBuilder sb = new StringBuilder();
-        sb.append(String.format(START_CMD, COMPONENT));
-        sb.append(String.format(INTENT_STRING_EXTRA, "benchmark_name", benchmark));
-        sb.append(String.format(INTENT_BOOLEAN_EXTRA, "offscreen", false));
-        sb.append(String.format(INTENT_INTEGER_EXTRA, "num_frames", 1000));
-        sb.append(String.format(INTENT_INTEGER_EXTRA, "num_iterations", 1));
-        sb.append(String.format(INTENT_INTEGER_EXTRA, "timeout", 10000));
-        final String startCommand = sb.toString();
-        final String stopCommand = String.format(STOP_CMD, PACKAGE);
-
-        Log.i(TAG, "Start command: " + startCommand);
-        Log.i(TAG, "Stop command: " + stopCommand);
-
-        setIteration(NUM_ITERATIONS);
-        for (int i = 0; i < NUM_ITERATIONS; i++) {
-            // Stop any existing instances
-            runShellCommand(stopCommand);
-            // Start activity
-            runShellCommand(startCommand);
-
-            // Wait for the activity to start
-            sleep(SLEEP_TIME / 2);
-
-            // Start systrace
-            startTrace(mTestCaseName, i);
-
-            // Clear SurfaceFlinger buffer
-            Log.i(TAG, "Clearing SurfaceFlinger buffer");
-            SurfaceFlingerHelper.clearBuffer(APP_WINDOW_NAME);
-
-            // This is where user interactions would go, in this case just sleep
-            sleep(SLEEP_TIME);
-
-            // Dump SurfaceFlinger buffer
-            Log.i(TAG, "Dumping SurfaceFlinger buffer");
-            boolean result = SurfaceFlingerHelper.dumpFrameLatency(APP_WINDOW_NAME, true);
-            assertTrue("SurfaceFlingerHelper could not get timestamps", result);
-
-            // Stop systrace
-            endTrace();
-
-            // Record results
-            recordResults(mTestCaseName, i);
-        }
-        // Save aggregated results
-        saveResults(mTestCaseName);
-        // Stop any remaining instances
-        runShellCommand(stopCommand);
-    }
-}
diff --git a/suite/cts/hostTests/jank/src/com/android/cts/jank/CtsHostJankTest.java b/suite/cts/hostTests/jank/src/com/android/cts/jank/CtsHostJankTest.java
deleted file mode 100644
index e196bfb..0000000
--- a/suite/cts/hostTests/jank/src/com/android/cts/jank/CtsHostJankTest.java
+++ /dev/null
@@ -1,147 +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.jank;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.tradefed.util.HostReportLog;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.ddmlib.IShellOutputReceiver;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import java.io.File;
-import java.util.HashMap;
-import java.util.Scanner;
-
-public class CtsHostJankTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
-
-    private static final String TAG = CtsHostJankTest.class.getSimpleName();
-    private static final String DEVICE_LOCATION = "/data/local/tmp/";
-    // FIXME uiautomator is deprecated and does not support --abi flag
-    private static final String RUN_UI_AUTOMATOR_CMD = "uiautomator runtest %s -c %s";
-    private final String mHostTestClass;
-    private final String mDeviceTestClass;
-    private final String mJarName;
-    private final String mJarPath;
-    protected ITestDevice mDevice;
-    protected CtsBuildHelper mBuild;
-    protected IAbi mAbi;
-
-    public CtsHostJankTest(String jarName, String deviceTestClass, String hostTestClass) {
-        this.mHostTestClass = hostTestClass;
-        this.mDeviceTestClass = deviceTestClass;
-        this.mJarName = jarName;
-        this.mJarPath = DEVICE_LOCATION + jarName;
-    }
-
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mDevice = getDevice();
-        // Push jar to device.
-        File jarFile = mBuild.getTestApp(mJarName);
-        boolean result = mDevice.pushFile(jarFile, mJarPath);
-        assertTrue("Failed to push file to " + mJarPath, result);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        // Delete jar from device.
-        mDevice.executeShellCommand("rm " + mJarPath);
-        super.tearDown();
-    }
-
-    public void runUiAutomatorTest(String testName) throws Exception {
-        // Delete any existing result files
-        mDevice.executeShellCommand("rm -r " + DEVICE_LOCATION + "*.txt");
-
-        // Run ui automator test.
-        mDevice.executeShellCommand(
-                String.format(RUN_UI_AUTOMATOR_CMD, mJarName, mDeviceTestClass + "#" + testName),
-                new IShellOutputReceiver() {
-                    private StringBuilder sb = new StringBuilder();
-
-                    @Override
-                    public void addOutput(byte[] data, int offset, int length) {
-                        byte[] raw = new byte[length];
-                        for (int i = 0; i < length; i++) {
-                            raw[i] = data[i + offset];
-                        }
-                        sb.append(new String(raw));
-                    }
-
-                    @Override
-                    public void flush() {
-                        Log.logAndDisplay(LogLevel.INFO, TAG, sb.toString());
-                    }
-
-                    @Override
-                    public boolean isCancelled() {
-                        return false;
-                    }
-                });
-
-        // Pull result file across
-        File result = mDevice.pullFile(DEVICE_LOCATION + "UiJankinessTestsOutput.txt");
-        assertNotNull("Couldn't get result file", result);
-        // Parse result file
-        Scanner in = new Scanner(result);
-        HashMap<String, Double> results = new HashMap<String, Double>(4);
-        while (in.hasNextLine()) {
-            String[] parts = in.nextLine().split(":");
-            if (parts.length == 2) {
-                results.put(parts[0], Double.parseDouble(parts[1]));
-            }
-        }
-        in.close();
-        Log.logAndDisplay(LogLevel.INFO, TAG, "Results: " + results);
-        assertEquals("Could not parse the results file: ", 4, results.size());
-
-        double avgNumJanks = results.get("average number of jankiness");
-        double maxNumJanks = results.get("max number of jankiness");
-        double avgFrameRate = results.get("average frame rate");
-        double avgMaxAccFrames = results.get("average of max accumulated frames");
-
-        // Create and deliver the report.
-        HostReportLog report = new HostReportLog(mDevice.getSerialNumber(), mAbi.getName(),
-                mHostTestClass + "#" + testName);
-        report.printValue(
-                "Average Frame Rate", avgFrameRate, ResultType.HIGHER_BETTER, ResultUnit.COUNT);
-        report.printValue("Average of Maximum Accumulated Frames", avgMaxAccFrames,
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-        report.printValue(
-                "Maximum Number of Janks", maxNumJanks, ResultType.LOWER_BETTER, ResultUnit.COUNT);
-        report.printSummary(
-                "Average Number of Janks", avgNumJanks, ResultType.LOWER_BETTER, ResultUnit.SCORE);
-        report.deliverReportToHost();
-    }
-
-}
diff --git a/suite/cts/hostTests/jank/src/com/android/cts/jank/opengl/CtsHostJankOpenGl.java b/suite/cts/hostTests/jank/src/com/android/cts/jank/opengl/CtsHostJankOpenGl.java
deleted file mode 100644
index 2942ecf..0000000
--- a/suite/cts/hostTests/jank/src/com/android/cts/jank/opengl/CtsHostJankOpenGl.java
+++ /dev/null
@@ -1,65 +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.jank.opengl;
-
-import com.android.cts.jank.CtsHostJankTest;
-import com.android.cts.util.AbiUtils;
-import java.io.File;
-
-public class CtsHostJankOpenGl extends CtsHostJankTest {
-
-    private static final String APK_PACKAGE = "com.android.cts";
-    private static final String APK = "CtsDeviceOpenGl.apk";
-    private static final String PACKAGE = "com.android.cts.jank.opengl";
-    private static final String HOST_CLASS = CtsHostJankOpenGl.class.getName();
-    private static final String DEVICE_CLASS = PACKAGE + ".CtsDeviceJankOpenGl";
-    private static final String JAR_NAME = "CtsDeviceJank.jar";
-
-    public CtsHostJankOpenGl() {
-        super(JAR_NAME, DEVICE_CLASS, HOST_CLASS);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // Install the app.
-        mDevice.uninstallPackage(APK_PACKAGE);
-        File app = mBuild.getTestApp(APK);
-        String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-        mDevice.installPackage(app, false, options);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        // Uninstall the app.
-        mDevice.uninstallPackage(APK_PACKAGE);
-        super.tearDown();
-    }
-
-    public void testFullPipeline() throws Exception {
-        runUiAutomatorTest("testFullPipeline");
-    }
-
-    public void testPixelOutput() throws Exception {
-        runUiAutomatorTest("testPixelOutput");
-    }
-
-    public void testShaderPerf() throws Exception {
-        runUiAutomatorTest("testShaderPerf");
-    }
-
-    public void testContextSwitch() throws Exception {
-        runUiAutomatorTest("testContextSwitch");
-    }
-}
diff --git a/suite/cts/hostTests/uihost/.gitignore b/suite/cts/hostTests/uihost/.gitignore
deleted file mode 100644
index 5e56e04..0000000
--- a/suite/cts/hostTests/uihost/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/bin
diff --git a/suite/cts/hostTests/uihost/Android.mk b/suite/cts/hostTests/uihost/Android.mk
deleted file mode 100644
index 67ebcbb..0000000
--- a/suite/cts/hostTests/uihost/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := CtsHostUi
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_CTS_TEST_PACKAGE := com.android.cts.uihost
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/suite/cts/hostTests/uihost/appA/Android.mk b/suite/cts/hostTests/uihost/appA/Android.mk
deleted file mode 100644
index 17f076f..0000000
--- a/suite/cts/hostTests/uihost/appA/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceTaskswitchingAppA
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/suite/cts/hostTests/uihost/appA/AndroidManifest.xml b/suite/cts/hostTests/uihost/appA/AndroidManifest.xml
deleted file mode 100644
index b97325c..0000000
--- a/suite/cts/hostTests/uihost/appA/AndroidManifest.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.taskswitching.appa" >
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
-    <application>
-        <activity
-            android:name=".AppAActivity"
-            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
-            android:screenOrientation="portrait" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-
-</manifest>
\ No newline at end of file
diff --git a/suite/cts/hostTests/uihost/appA/src/com/android/cts/taskswitching/appa/AppAActivity.java b/suite/cts/hostTests/uihost/appA/src/com/android/cts/taskswitching/appa/AppAActivity.java
deleted file mode 100644
index a4207a0..0000000
--- a/suite/cts/hostTests/uihost/appA/src/com/android/cts/taskswitching/appa/AppAActivity.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.taskswitching.appa;
-
-
-import android.app.ListActivity;
-import android.content.Intent;
-
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.WindowManager;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-
-/**
- * Simple activity to notify completion via broadcast after onResume.
- * This is for measuring taskswitching time between two apps.
- */
-public class AppAActivity extends ListActivity {
-    static final String TAG = "AppAActivity";
-    private static final int NUMBER_ELEMENTS = 1000;
-    private static final String TASKSWITCHING_INTENT = "com.android.cts.taskswitching.appa";
-    private Handler mHandler;
-
-    private String[] mItems = new String[NUMBER_ELEMENTS];
-
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
-        for (int i = 0; i < NUMBER_ELEMENTS; i++) {
-            mItems[i] = "A" + Integer.toString(i);
-        }
-        setListAdapter(new ArrayAdapter<String>(this,
-                android.R.layout.simple_list_item_1, mItems));
-        ListView view = getListView();
-        mHandler = new Handler();
-    }
-
-    public void onResume() {
-        super.onResume();
-        mHandler.post(new Runnable() {
-
-            @Override
-            public void run() {
-                Intent intent = new Intent(TASKSWITCHING_INTENT);
-                sendBroadcast(intent);
-            }
-        });
-    }
-}
diff --git a/suite/cts/hostTests/uihost/appB/Android.mk b/suite/cts/hostTests/uihost/appB/Android.mk
deleted file mode 100644
index ebb36d2..0000000
--- a/suite/cts/hostTests/uihost/appB/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceTaskswitchingAppB
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/suite/cts/hostTests/uihost/appB/AndroidManifest.xml b/suite/cts/hostTests/uihost/appB/AndroidManifest.xml
deleted file mode 100644
index b96afe5..0000000
--- a/suite/cts/hostTests/uihost/appB/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.taskswitching.appb">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
-    <application>
-        <activity
-            android:name=".AppBActivity"
-            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
-            android:screenOrientation="portrait" >
-
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER"/>
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/suite/cts/hostTests/uihost/appB/src/com/android/cts/taskswitching/appb/AppBActivity.java b/suite/cts/hostTests/uihost/appB/src/com/android/cts/taskswitching/appb/AppBActivity.java
deleted file mode 100644
index 4df5e98..0000000
--- a/suite/cts/hostTests/uihost/appB/src/com/android/cts/taskswitching/appb/AppBActivity.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.taskswitching.appb;
-
-import android.app.ListActivity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.WindowManager;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-
-/**
- * Simple activity to notify completion via broadcast after onResume.
- * This is for measuring taskswitching time between two apps.
- */
-public class AppBActivity extends ListActivity {
-    static final String TAG = "AppBActivity";
-    private static final int NUMBER_ELEMENTS = 1000;
-    private static final String TASKSWITCHING_INTENT = "com.android.cts.taskswitching.appb";
-    private Handler mHandler;
-
-    private String[] mItems = new String[NUMBER_ELEMENTS];
-
-    public void onCreate(Bundle icicle)
-    {
-        super.onCreate(icicle);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
-        for (int i = 0; i < NUMBER_ELEMENTS; i++) {
-            mItems[i] = "B" + Integer.toString(i);
-        }
-        setListAdapter(new ArrayAdapter<String>(this,
-                android.R.layout.simple_list_item_1, mItems));
-        ListView view = getListView();
-        mHandler = new Handler();
-    }
-
-    public void onResume()
-    {
-        super.onResume();
-        mHandler.post(new Runnable() {
-
-            @Override
-            public void run() {
-                Intent intent = new Intent(TASKSWITCHING_INTENT);
-                sendBroadcast(intent);
-            }
-        });
-    }
-}
diff --git a/suite/cts/hostTests/uihost/control/Android.mk b/suite/cts/hostTests/uihost/control/Android.mk
deleted file mode 100644
index 4de9ae8..0000000
--- a/suite/cts/hostTests/uihost/control/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceTaskswitchingControl
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/suite/cts/hostTests/uihost/control/AndroidManifest.xml b/suite/cts/hostTests/uihost/control/AndroidManifest.xml
deleted file mode 100644
index e4b10f2..0000000
--- a/suite/cts/hostTests/uihost/control/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.taskswitching.control">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-    <instrumentation
-        android:targetPackage="com.android.cts.taskswitching.control"
-        android:name="android.support.test.runner.AndroidJUnitRunner" >
-        <meta-data
-            android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
-    </instrumentation>
-</manifest>
diff --git a/suite/cts/hostTests/uihost/control/src/com/android/cts/taskswitching/control/TaskswitchingDeviceTest.java b/suite/cts/hostTests/uihost/control/src/com/android/cts/taskswitching/control/TaskswitchingDeviceTest.java
deleted file mode 100644
index bdb3132..0000000
--- a/suite/cts/hostTests/uihost/control/src/com/android/cts/taskswitching/control/TaskswitchingDeviceTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.taskswitching.control;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-
-import com.android.cts.util.MeasureRun;
-import com.android.cts.util.MeasureTime;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import android.cts.util.CtsAndroidTestCase;
-import com.android.cts.util.Stat;
-
-
-/**
- * Device test which actually launches two apps sequentially and
- * measure time for switching.
- * Completion of launch is notified via broadcast.
- */
-public class TaskswitchingDeviceTest extends CtsAndroidTestCase {
-    private static final String PKG_A = "com.android.cts.taskswitching.appa";
-    private static final String PKG_B = "com.android.cts.taskswitching.appb";
-    private static final String ACTIVITY_A = "AppAActivity";
-    private static final String ACTIVITY_B = "AppBActivity";
-    private static final long TASK_SWITCHING_WAIT_TIME = 5;
-    private final AppBroadcastReceiver mReceiverA = new AppBroadcastReceiver();
-    private final AppBroadcastReceiver mReceiverB = new AppBroadcastReceiver();
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        startActivity(PKG_A, ACTIVITY_A);
-        startActivity(PKG_B, ACTIVITY_B);
-        IntentFilter filterA = new IntentFilter();
-        filterA.addAction(PKG_A);
-        IntentFilter filterB = new IntentFilter();
-        filterB.addAction(PKG_B);
-        getContext().registerReceiver(mReceiverA, filterA);
-        getContext().registerReceiver(mReceiverB, filterB);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        getContext().unregisterReceiver(mReceiverA);
-        getContext().unregisterReceiver(mReceiverB);
-        super.tearDown();
-    }
-
-    public void testMeasureTaskSwitching() throws Exception {
-        final int NUMBER_REPEAT = 10;
-        final int SWITCHING_PER_ONE_TRY = 10;
-
-        double[] results = MeasureTime.measure(NUMBER_REPEAT, new MeasureRun() {
-
-            @Override
-            public void run(int i) throws Exception {
-                for (int j = 0; j < SWITCHING_PER_ONE_TRY; j++) {
-                    startActivity(PKG_A, ACTIVITY_A);
-                    assertTrue(mReceiverA.waitForBroadcast(TASK_SWITCHING_WAIT_TIME));
-                    startActivity(PKG_B, ACTIVITY_B);
-                    assertTrue(mReceiverB.waitForBroadcast(TASK_SWITCHING_WAIT_TIME));
-                }
-            }
-        });
-        getReportLog().printArray("taskswitching time", results, ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-        Stat.StatResult stat = Stat.getStat(results);
-        getReportLog().printSummary("taskswitching time", stat.mAverage,
-                ResultType.LOWER_BETTER, ResultUnit.MS);
-    }
-
-    private void startActivity(String packageName, String activityName) {
-        Context context = getContext();
-        Intent intent = new Intent();
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.addCategory(Intent.CATEGORY_LAUNCHER);
-        intent.setComponent(new ComponentName(packageName, packageName + "." + activityName));
-        context.startActivity(intent);
-    }
-
-    class AppBroadcastReceiver extends BroadcastReceiver {
-        private final Semaphore mSemaphore = new Semaphore(0);
-
-        public boolean waitForBroadcast(long timeoutInSec) throws InterruptedException {
-            return mSemaphore.tryAcquire(timeoutInSec, TimeUnit.SECONDS);
-        }
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            mSemaphore.release();
-        }
-    }
-}
diff --git a/suite/cts/hostTests/uihost/src/com/android/cts/uihost/InstallTimeTest.java b/suite/cts/hostTests/uihost/src/com/android/cts/uihost/InstallTimeTest.java
deleted file mode 100644
index 75a2e92..0000000
--- a/suite/cts/hostTests/uihost/src/com/android/cts/uihost/InstallTimeTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.uihost;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.tradefed.util.HostReportLog;
-import com.android.cts.util.AbiUtils;
-import com.android.cts.util.MeasureRun;
-import com.android.cts.util.MeasureTime;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.Stat;
-import com.android.ddmlib.Log;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import java.io.File;
-
-
-/**
- * Test to measure installation time of a APK.
- */
-public class InstallTimeTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
-    private CtsBuildHelper mBuild;
-    private ITestDevice mDevice;
-    private IAbi mAbi;
-
-    private static final String TAG = "InstallTimeTest";
-    static final String PACKAGE = "com.replica.replicaisland";
-    static final String APK = "com.replica.replicaisland.apk";
-    private static final double OUTLIER_THRESHOLD = 0.1;
-
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mDevice = getDevice();
-    }
-
-
-    @Override
-    protected void tearDown() throws Exception {
-        mDevice.uninstallPackage(PACKAGE);
-        super.tearDown();
-    }
-
-    public void testInstallTime() throws Exception {
-        HostReportLog report = new HostReportLog(mDevice.getSerialNumber(), mAbi.getName(),
-                ReportLog.getClassMethodNames());
-        final int NUMBER_REPEAT = 10;
-        final CtsBuildHelper build = mBuild;
-        final ITestDevice device = mDevice;
-        double[] result = MeasureTime.measure(NUMBER_REPEAT, new MeasureRun() {
-            @Override
-            public void prepare(int i) throws Exception {
-                device.uninstallPackage(PACKAGE);
-            }
-            @Override
-            public void run(int i) throws Exception {
-                File app = build.getTestApp(APK);
-                String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-                device.installPackage(app, false, options);
-            }
-        });
-        report.printArray("install time", result, ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-        Stat.StatResult stat = Stat.getStatWithOutlierRejection(result, OUTLIER_THRESHOLD);
-        if (stat.mDataCount != result.length) {
-            Log.w(TAG, "rejecting " + (result.length - stat.mDataCount) + " outliers");
-        }
-        report.printSummary("install time", stat.mAverage, ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-        report.deliverReportToHost();
-    }
-
-}
diff --git a/suite/cts/hostTests/uihost/src/com/android/cts/uihost/TaskSwitchingTest.java b/suite/cts/hostTests/uihost/src/com/android/cts/uihost/TaskSwitchingTest.java
deleted file mode 100644
index 2d33436..0000000
--- a/suite/cts/hostTests/uihost/src/com/android/cts/uihost/TaskSwitchingTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.uihost;
-
-import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.tradefed.util.CtsHostStore;
-import com.android.cts.tradefed.util.HostReportLog;
-import com.android.cts.util.AbiUtils;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.TimeoutReq;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
-import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.ddmlib.testrunner.TestRunResult;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.result.CollectingTestListener;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import java.io.File;
-import java.util.Map;
-
-
-/**
- * Measure time to taskswitching between two Apps: A & B
- * Actual test is done in device, but this host side code installs all necessary APKs
- * and starts device test which is in CtsDeviceTaskswitchingControl.
- */
-public class TaskSwitchingTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
-    private static final String TAG = "TaskSwitchingTest";
-    private final static String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
-    private CtsBuildHelper mBuild;
-    private ITestDevice mDevice;
-    private String mCtsReport = null;
-    private IAbi mAbi;
-
-    static final String[] PACKAGES = {
-        "com.android.cts.taskswitching.control",
-        "com.android.cts.taskswitching.appa",
-        "com.android.cts.taskswitching.appb"
-    };
-    static final String[] APKS = {
-        "CtsDeviceTaskswitchingControl.apk",
-        "CtsDeviceTaskswitchingAppA.apk",
-        "CtsDeviceTaskswitchingAppB.apk"
-    };
-
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mDevice = getDevice();
-        String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-        for (int i = 0; i < PACKAGES.length; i++) {
-            mDevice.uninstallPackage(PACKAGES[i]);
-            File app = mBuild.getTestApp(APKS[i]);
-            mDevice.installPackage(app, false, options);
-        }
-    }
-
-
-    @Override
-    protected void tearDown() throws Exception {
-        for (int i = 0; i < PACKAGES.length; i++) {
-            mDevice.uninstallPackage(PACKAGES[i]);
-        }
-        super.tearDown();
-    }
-
-    @TimeoutReq(minutes = 30)
-    public void testTaskswitching() throws Exception {
-        // TODO is this used?
-        HostReportLog report = new HostReportLog(mDevice.getSerialNumber(), mAbi.getName(),
-                ReportLog.getClassMethodNames());
-        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(PACKAGES[0], RUNNER,
-                mDevice.getIDevice());
-        LocalListener listener = new LocalListener();
-        mDevice.runInstrumentationTests(testRunner, listener);
-        TestRunResult result = listener.getCurrentRunResults();
-        if (result.isRunFailure()) {
-            fail(result.getRunFailureMessage());
-        }
-        assertNotNull("no performance data", mCtsReport);
-        CtsHostStore.storeCtsResult(mDevice.getSerialNumber(), mAbi.getName(),
-                ReportLog.getClassMethodNames(), mCtsReport);
-
-    }
-
-    public class LocalListener extends CollectingTestListener {
-        @Override
-        public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
-            // necessary as testMetrics passed from CollectingTestListerner is empty
-            if (testMetrics.containsKey("CTS_TEST_RESULT")) {
-                mCtsReport = testMetrics.get("CTS_TEST_RESULT");
-            }
-            super.testEnded(test, testMetrics);
-        }
-    }
-}
diff --git a/test_defs.sh b/test_defs.sh
new file mode 100644
index 0000000..5d5090d
--- /dev/null
+++ b/test_defs.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# Copyright (C) 2015 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.
+
+# Common tools for running unit tests of the compatibility libs
+
+JAR_DIR=${ANDROID_HOST_OUT}/framework
+TF_CONSOLE=com.android.tradefed.command.Console
+
+COMMON_JARS="
+    ddmlib-prebuilt\
+    hosttestlib\
+    tradefed-prebuilt"
+
+checkFile() {
+    if [ ! -f "$1" ]; then
+        echo "Unable to locate $1"
+        exit
+    fi;
+}
+
+build_jar_path() {
+    JAR_PATH=
+    for JAR in ${2} ${COMMON_JARS}; do
+        checkFile ${1}/${JAR}.jar
+        JAR_PATH=${JAR_PATH}:${1}/${JAR}.jar
+    done
+}
+
+run_tests() {
+    build_jar_path "${JAR_DIR}" "${2}"
+    for CLASS in ${1}; do
+        java $RDBG_FLAG -cp ${JAR_PATH} ${TF_CONSOLE} run singleCommand host -n --class ${CLASS} ${3}
+    done
+}
diff --git a/tests/JobScheduler/Android.mk b/tests/JobScheduler/Android.mk
index 499abded..fe5865d 100755
--- a/tests/JobScheduler/Android.mk
+++ b/tests/JobScheduler/Android.mk
@@ -26,8 +26,11 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # Must match the package name in CtsTestCaseList.mk
-LOCAL_PACKAGE_NAME := CtsJobSchedulerDeviceTestCases
+LOCAL_PACKAGE_NAME := CtsJobSchedulerTestCases
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/JobScheduler/AndroidManifest.xml b/tests/JobScheduler/AndroidManifest.xml
index 17cf399..2078978 100755
--- a/tests/JobScheduler/AndroidManifest.xml
+++ b/tests/JobScheduler/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.jobscheduler.cts.deviceside">
+    package="android.jobscheduler.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -35,7 +35,7 @@
     <instrumentation
         android:name="android.support.test.runner.AndroidJUnitRunner"
         android:label="JobScheduler device-side tests"
-        android:targetPackage="android.jobscheduler.cts.deviceside" >
+        android:targetPackage="android.jobscheduler.cts" >
         <meta-data
             android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/JobScheduler/AndroidTest.xml b/tests/JobScheduler/AndroidTest.xml
new file mode 100644
index 0000000..57a2f30
--- /dev/null
+++ b/tests/JobScheduler/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Job Scheduler test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsJobSchedulerTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.jobscheduler.cts" />
+        <option name="runtime-hint" value="2m" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/acceleration/Android.mk b/tests/acceleration/Android.mk
index f36b64b..87aa7c5 100644
--- a/tests/acceleration/Android.mk
+++ b/tests/acceleration/Android.mk
@@ -24,10 +24,15 @@
 
 LOCAL_PROGUARD_ENABLED := disabled
 
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := CtsAccelerationTestStubs
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_PACKAGE_NAME := CtsAccelerationTestCases
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_CTS_SUPPORT_PACKAGE)
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/acceleration/AndroidManifest.xml b/tests/acceleration/AndroidManifest.xml
index f92b736..1a21554 100644
--- a/tests/acceleration/AndroidManifest.xml
+++ b/tests/acceleration/AndroidManifest.xml
@@ -15,15 +15,25 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.acceleration.stub">
+        package="android.acceleration.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
 
     <application android:hardwareAccelerated="true">
-        <activity android:name="android.acceleration.cts.HardwareAcceleratedActivity" />
-        <activity android:name="android.acceleration.cts.SoftwareAcceleratedActivity"
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="android.acceleration.HardwareAcceleratedActivity" />
+        <activity android:name="android.acceleration.SoftwareAcceleratedActivity"
                 android:hardwareAccelerated="false" />
-        <activity android:name="android.acceleration.cts.WindowFlagHardwareAcceleratedActivity"
+        <activity android:name="android.acceleration.WindowFlagHardwareAcceleratedActivity"
                 android:hardwareAccelerated="false" />
     </application>
 
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="android.acceleration.cts"
+            android:label="Tests for the Hardware Acceleration APIs." >
+        <meta-data android:name="listener"
+                android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
 </manifest>
 
diff --git a/tests/acceleration/AndroidTest.xml b/tests/acceleration/AndroidTest.xml
new file mode 100644
index 0000000..1786c8e
--- /dev/null
+++ b/tests/acceleration/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Acceleration test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAccelerationTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.acceleration.cts" />
+    </test>
+</configuration>
diff --git a/tests/acceleration/res/layout/acceleration.xml b/tests/acceleration/res/layout/acceleration.xml
index 8dc027a..5127507 100644
--- a/tests/acceleration/res/layout/acceleration.xml
+++ b/tests/acceleration/res/layout/acceleration.xml
@@ -18,25 +18,25 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         >
-    <android.acceleration.cts.AcceleratedView android:id="@+id/hardware_accelerated_view"
+    <android.acceleration.AcceleratedView android:id="@+id/hardware_accelerated_view"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:layerType="hardware"
             />
-    <android.acceleration.cts.AcceleratedView android:id="@+id/software_accelerated_view"
+    <android.acceleration.AcceleratedView android:id="@+id/software_accelerated_view"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:layerType="software"
             />
     <!-- Acceleration will be set via manual setLayerType calls from the activity. -->
-    <android.acceleration.cts.AcceleratedView android:id="@+id/manual_hardware_accelerated_view"
+    <android.acceleration.AcceleratedView android:id="@+id/manual_hardware_accelerated_view"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             />
-    <android.acceleration.cts.AcceleratedView android:id="@+id/manual_software_accelerated_view"
+    <android.acceleration.AcceleratedView android:id="@+id/manual_software_accelerated_view"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
diff --git a/tests/acceleration/src/android/acceleration/AcceleratedView.java b/tests/acceleration/src/android/acceleration/AcceleratedView.java
new file mode 100644
index 0000000..7134a76
--- /dev/null
+++ b/tests/acceleration/src/android/acceleration/AcceleratedView.java
@@ -0,0 +1,67 @@
+/*
+ * 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 android.acceleration;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class AcceleratedView extends View {
+
+    private final CountDownLatch mDrawLatch = new CountDownLatch(1);
+
+    private boolean mIsHardwareAccelerated;
+
+    public AcceleratedView(Context context) {
+        super(context);
+    }
+
+    public AcceleratedView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AcceleratedView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        synchronized (this) {
+            mIsHardwareAccelerated = canvas.isHardwareAccelerated();
+        }
+        mDrawLatch.countDown();
+    }
+
+    public boolean isCanvasHardwareAccelerated() {
+        try {
+            if (mDrawLatch.await(1, TimeUnit.SECONDS)) {
+                synchronized (this) {
+                    return mIsHardwareAccelerated;
+                }
+            } else {
+                throw new IllegalStateException("View was not drawn...");
+            }
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/tests/acceleration/src/android/acceleration/BaseAcceleratedActivity.java b/tests/acceleration/src/android/acceleration/BaseAcceleratedActivity.java
new file mode 100644
index 0000000..262b43e
--- /dev/null
+++ b/tests/acceleration/src/android/acceleration/BaseAcceleratedActivity.java
@@ -0,0 +1,65 @@
+/*
+ * 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 android.acceleration;
+
+import android.acceleration.cts.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public abstract class BaseAcceleratedActivity extends Activity {
+
+    private AcceleratedView mHardwareAcceleratedView;
+    private AcceleratedView mSoftwareAcceleratedView;
+
+    private AcceleratedView mManualHardwareAcceleratedView;
+    private AcceleratedView mManualSoftwareAcceleratedView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.acceleration);
+
+        mHardwareAcceleratedView = (AcceleratedView) findViewById(R.id.hardware_accelerated_view);
+        mSoftwareAcceleratedView = (AcceleratedView) findViewById(R.id.software_accelerated_view);
+
+        mManualHardwareAcceleratedView =
+            (AcceleratedView) findViewById(R.id.manual_hardware_accelerated_view);
+        mManualSoftwareAcceleratedView =
+            (AcceleratedView) findViewById(R.id.manual_software_accelerated_view);
+
+        mManualHardwareAcceleratedView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        mManualSoftwareAcceleratedView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+    }
+
+    public AcceleratedView getHardwareAcceleratedView() {
+        return mHardwareAcceleratedView;
+    }
+
+    public AcceleratedView getSoftwareAcceleratedView() {
+        return mSoftwareAcceleratedView;
+    }
+
+    public AcceleratedView getManualHardwareAcceleratedView() {
+        return mManualHardwareAcceleratedView;
+    }
+
+    public AcceleratedView getManualSoftwareAcceleratedView() {
+        return mManualSoftwareAcceleratedView;
+    }
+}
diff --git a/tests/acceleration/src/android/acceleration/HardwareAcceleratedActivity.java b/tests/acceleration/src/android/acceleration/HardwareAcceleratedActivity.java
new file mode 100644
index 0000000..9122565
--- /dev/null
+++ b/tests/acceleration/src/android/acceleration/HardwareAcceleratedActivity.java
@@ -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.
+ */
+
+package android.acceleration;
+
+public class HardwareAcceleratedActivity extends BaseAcceleratedActivity {
+}
diff --git a/tests/acceleration/src/android/acceleration/SoftwareAcceleratedActivity.java b/tests/acceleration/src/android/acceleration/SoftwareAcceleratedActivity.java
new file mode 100644
index 0000000..7555862
--- /dev/null
+++ b/tests/acceleration/src/android/acceleration/SoftwareAcceleratedActivity.java
@@ -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.
+ */
+
+package android.acceleration;
+
+public class SoftwareAcceleratedActivity extends BaseAcceleratedActivity {
+}
diff --git a/tests/acceleration/src/android/acceleration/WindowFlagHardwareAcceleratedActivity.java b/tests/acceleration/src/android/acceleration/WindowFlagHardwareAcceleratedActivity.java
new file mode 100644
index 0000000..d448334
--- /dev/null
+++ b/tests/acceleration/src/android/acceleration/WindowFlagHardwareAcceleratedActivity.java
@@ -0,0 +1,30 @@
+/*
+ * 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 android.acceleration;
+
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class WindowFlagHardwareAcceleratedActivity extends BaseAcceleratedActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+    }
+}
diff --git a/tests/acceleration/src/android/acceleration/cts/AcceleratedView.java b/tests/acceleration/src/android/acceleration/cts/AcceleratedView.java
deleted file mode 100644
index 7d749a1..0000000
--- a/tests/acceleration/src/android/acceleration/cts/AcceleratedView.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 android.acceleration.cts;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.View;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class AcceleratedView extends View {
-
-    private final CountDownLatch mDrawLatch = new CountDownLatch(1);
-
-    private boolean mIsHardwareAccelerated;
-
-    public AcceleratedView(Context context) {
-        super(context);
-    }
-
-    public AcceleratedView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public AcceleratedView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-        synchronized (this) {
-            mIsHardwareAccelerated = canvas.isHardwareAccelerated();
-        }
-        mDrawLatch.countDown();
-    }
-
-    public boolean isCanvasHardwareAccelerated() {
-        try {
-            if (mDrawLatch.await(1, TimeUnit.SECONDS)) {
-                synchronized (this) {
-                    return mIsHardwareAccelerated;
-                }
-            } else {
-                throw new IllegalStateException("View was not drawn...");
-            }
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
-    }
-}
diff --git a/tests/acceleration/src/android/acceleration/cts/BaseAcceleratedActivity.java b/tests/acceleration/src/android/acceleration/cts/BaseAcceleratedActivity.java
deleted file mode 100644
index 8ef6a8e..0000000
--- a/tests/acceleration/src/android/acceleration/cts/BaseAcceleratedActivity.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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 android.acceleration.cts;
-
-import com.android.cts.acceleration.stub.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-
-abstract class BaseAcceleratedActivity extends Activity {
-
-    private AcceleratedView mHardwareAcceleratedView;
-    private AcceleratedView mSoftwareAcceleratedView;
-
-    private AcceleratedView mManualHardwareAcceleratedView;
-    private AcceleratedView mManualSoftwareAcceleratedView;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.acceleration);
-
-        mHardwareAcceleratedView = (AcceleratedView) findViewById(R.id.hardware_accelerated_view);
-        mSoftwareAcceleratedView = (AcceleratedView) findViewById(R.id.software_accelerated_view);
-
-        mManualHardwareAcceleratedView =
-            (AcceleratedView) findViewById(R.id.manual_hardware_accelerated_view);
-        mManualSoftwareAcceleratedView =
-            (AcceleratedView) findViewById(R.id.manual_software_accelerated_view);
-
-        mManualHardwareAcceleratedView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-        mManualSoftwareAcceleratedView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-    }
-
-    public AcceleratedView getHardwareAcceleratedView() {
-        return mHardwareAcceleratedView;
-    }
-
-    public AcceleratedView getSoftwareAcceleratedView() {
-        return mSoftwareAcceleratedView;
-    }
-
-    public AcceleratedView getManualHardwareAcceleratedView() {
-        return mManualHardwareAcceleratedView;
-    }
-
-    public AcceleratedView getManualSoftwareAcceleratedView() {
-        return mManualSoftwareAcceleratedView;
-    }
-}
diff --git a/tests/acceleration/src/android/acceleration/cts/BaseAccelerationTest.java b/tests/acceleration/src/android/acceleration/cts/BaseAccelerationTest.java
new file mode 100644
index 0000000..c6e94ec
--- /dev/null
+++ b/tests/acceleration/src/android/acceleration/cts/BaseAccelerationTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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 android.acceleration.cts;
+
+import android.acceleration.AcceleratedView;
+import android.acceleration.BaseAcceleratedActivity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureInfo;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.View;
+
+abstract class BaseAccelerationTest<B extends BaseAcceleratedActivity>
+        extends ActivityInstrumentationTestCase2<B> {
+
+    protected B mActivity;
+
+    /** View with android:layerType="hardware" set */
+    protected AcceleratedView mHardwareView;
+
+    /** View with android:layerType="software" set */
+    protected AcceleratedView mSoftwareView;
+
+    /** View with setLayerType(HARDWARE) called */
+    protected AcceleratedView mManualHardwareView;
+
+    /** View with setLayerType(SOFTWARE) called */
+    protected AcceleratedView mManualSoftwareView;
+
+    BaseAccelerationTest(Class<B> clazz) {
+        super(clazz);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mHardwareView = mActivity.getHardwareAcceleratedView();
+        mSoftwareView = mActivity.getSoftwareAcceleratedView();
+        mManualHardwareView = mActivity.getManualHardwareAcceleratedView();
+        mManualSoftwareView = mActivity.getManualSoftwareAcceleratedView();
+    }
+
+    public void testNotAttachedView() {
+        // Views that are not attached can't be attached to an accelerated window.
+        View view = new View(mActivity);
+        assertFalse(view.isHardwareAccelerated());
+    }
+
+    protected static int getGlEsVersion(Context context) {
+        ActivityManager activityManager =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo();
+        if (configInfo.reqGlEsVersion != ConfigurationInfo.GL_ES_VERSION_UNDEFINED) {
+            return getMajorVersion(configInfo.reqGlEsVersion);
+        } else {
+            return 1; // Lack of property means OpenGL ES version 1
+        }
+    }
+
+    /** @see FeatureInfo#getGlEsVersion() */
+    private static int getMajorVersion(int glEsVersion) {
+        return ((glEsVersion & 0xffff0000) >> 16);
+    }
+}
diff --git a/tests/acceleration/src/android/acceleration/cts/HardwareAcceleratedActivity.java b/tests/acceleration/src/android/acceleration/cts/HardwareAcceleratedActivity.java
deleted file mode 100644
index bb26202..0000000
--- a/tests/acceleration/src/android/acceleration/cts/HardwareAcceleratedActivity.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * 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 android.acceleration.cts;
-
-public class HardwareAcceleratedActivity extends BaseAcceleratedActivity {
-}
diff --git a/tests/acceleration/src/android/acceleration/cts/HardwareAccelerationTest.java b/tests/acceleration/src/android/acceleration/cts/HardwareAccelerationTest.java
new file mode 100644
index 0000000..94089cc
--- /dev/null
+++ b/tests/acceleration/src/android/acceleration/cts/HardwareAccelerationTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 android.acceleration.cts;
+
+import android.acceleration.HardwareAcceleratedActivity;
+
+/**
+ * Test that uses an Activity with hardware acceleration enabled.
+ */
+public class HardwareAccelerationTest
+        extends BaseAccelerationTest<HardwareAcceleratedActivity> {
+
+    public HardwareAccelerationTest() {
+        super(HardwareAcceleratedActivity.class);
+    }
+
+    public void testIsHardwareAccelerated() {
+        // Hardware acceleration should be available on devices with GL ES 2 or higher...
+        if (getGlEsVersion(mActivity) >= 2) {
+            // Both of the views are attached to a hardware accelerated window
+            assertTrue(mHardwareView.isHardwareAccelerated());
+            assertTrue(mSoftwareView.isHardwareAccelerated());
+            assertTrue(mManualHardwareView.isHardwareAccelerated());
+            assertTrue(mManualSoftwareView.isHardwareAccelerated());
+
+            assertTrue(mHardwareView.isCanvasHardwareAccelerated());
+            assertFalse(mSoftwareView.isCanvasHardwareAccelerated());
+            assertTrue(mManualHardwareView.isCanvasHardwareAccelerated());
+            assertFalse(mManualSoftwareView.isCanvasHardwareAccelerated());
+        } else {
+            assertFalse(mHardwareView.isHardwareAccelerated());
+            assertFalse(mSoftwareView.isHardwareAccelerated());
+            assertFalse(mManualHardwareView.isHardwareAccelerated());
+            assertFalse(mManualSoftwareView.isHardwareAccelerated());
+
+            assertFalse(mHardwareView.isCanvasHardwareAccelerated());
+            assertFalse(mSoftwareView.isCanvasHardwareAccelerated());
+            assertFalse(mManualHardwareView.isCanvasHardwareAccelerated());
+            assertFalse(mManualSoftwareView.isCanvasHardwareAccelerated());
+        }
+    }
+}
diff --git a/tests/acceleration/src/android/acceleration/cts/SoftwareAcceleratedActivity.java b/tests/acceleration/src/android/acceleration/cts/SoftwareAcceleratedActivity.java
deleted file mode 100644
index 0a6a3df..0000000
--- a/tests/acceleration/src/android/acceleration/cts/SoftwareAcceleratedActivity.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * 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 android.acceleration.cts;
-
-public class SoftwareAcceleratedActivity extends BaseAcceleratedActivity {
-}
diff --git a/tests/acceleration/src/android/acceleration/cts/SoftwareAccelerationTest.java b/tests/acceleration/src/android/acceleration/cts/SoftwareAccelerationTest.java
new file mode 100644
index 0000000..4e12c1e
--- /dev/null
+++ b/tests/acceleration/src/android/acceleration/cts/SoftwareAccelerationTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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 android.acceleration.cts;
+
+import android.acceleration.SoftwareAcceleratedActivity;
+
+/**
+ * Test that uses an Activity with hardware acceleration explicitly disabled
+ * and makes sure that all views are rendered using software acceleration.
+ */
+public class SoftwareAccelerationTest
+        extends BaseAccelerationTest<SoftwareAcceleratedActivity> {
+
+    public SoftwareAccelerationTest() {
+        super(SoftwareAcceleratedActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+    }
+
+    public void testIsHardwareAccelerated() {
+        // Both of the views are not attached to a hardware accelerated window
+        assertFalse(mHardwareView.isHardwareAccelerated());
+        assertFalse(mSoftwareView.isHardwareAccelerated());
+        assertFalse(mManualHardwareView.isHardwareAccelerated());
+        assertFalse(mManualSoftwareView.isHardwareAccelerated());
+
+        assertFalse(mHardwareView.isCanvasHardwareAccelerated());
+        assertFalse(mSoftwareView.isCanvasHardwareAccelerated());
+        assertFalse(mManualHardwareView.isCanvasHardwareAccelerated());
+        assertFalse(mManualSoftwareView.isCanvasHardwareAccelerated());
+    }
+}
diff --git a/tests/acceleration/src/android/acceleration/cts/WindowFlagHardwareAcceleratedActivity.java b/tests/acceleration/src/android/acceleration/cts/WindowFlagHardwareAcceleratedActivity.java
deleted file mode 100644
index 9def8b7..0000000
--- a/tests/acceleration/src/android/acceleration/cts/WindowFlagHardwareAcceleratedActivity.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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 android.acceleration.cts;
-
-import android.os.Bundle;
-import android.view.WindowManager;
-
-public class WindowFlagHardwareAcceleratedActivity extends BaseAcceleratedActivity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
-                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
-    }
-}
diff --git a/tests/acceleration/src/android/acceleration/cts/WindowFlagHardwareAccelerationTest.java b/tests/acceleration/src/android/acceleration/cts/WindowFlagHardwareAccelerationTest.java
new file mode 100644
index 0000000..2070666
--- /dev/null
+++ b/tests/acceleration/src/android/acceleration/cts/WindowFlagHardwareAccelerationTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 android.acceleration.cts;
+
+import android.acceleration.WindowFlagHardwareAcceleratedActivity;
+
+/**
+ * Test that uses an Activity with hardware acceleration enabled.
+ */
+public class WindowFlagHardwareAccelerationTest
+        extends BaseAccelerationTest<WindowFlagHardwareAcceleratedActivity> {
+
+    public WindowFlagHardwareAccelerationTest() {
+        super(WindowFlagHardwareAcceleratedActivity.class);
+    }
+
+    public void testIsHardwareAccelerated() {
+        // Hardware acceleration should be available on devices with GL ES 2 or higher...
+        if (getGlEsVersion(mActivity) >= 2) {
+            // Both of the views are attached to a hardware accelerated window
+            assertTrue(mHardwareView.isHardwareAccelerated());
+            assertTrue(mSoftwareView.isHardwareAccelerated());
+            assertTrue(mManualHardwareView.isHardwareAccelerated());
+            assertTrue(mManualSoftwareView.isHardwareAccelerated());
+
+            assertTrue(mHardwareView.isCanvasHardwareAccelerated());
+            assertFalse(mSoftwareView.isCanvasHardwareAccelerated());
+            assertTrue(mManualHardwareView.isCanvasHardwareAccelerated());
+            assertFalse(mManualSoftwareView.isCanvasHardwareAccelerated());
+        } else {
+            assertFalse(mHardwareView.isHardwareAccelerated());
+            assertFalse(mSoftwareView.isHardwareAccelerated());
+            assertFalse(mManualHardwareView.isHardwareAccelerated());
+            assertFalse(mManualSoftwareView.isHardwareAccelerated());
+
+            assertFalse(mHardwareView.isCanvasHardwareAccelerated());
+            assertFalse(mSoftwareView.isCanvasHardwareAccelerated());
+            assertFalse(mManualHardwareView.isCanvasHardwareAccelerated());
+            assertFalse(mManualSoftwareView.isCanvasHardwareAccelerated());
+        }
+    }
+}
diff --git a/tests/accessibility/Android.mk b/tests/accessibility/Android.mk
index bddbb58..f324ad9 100644
--- a/tests/accessibility/Android.mk
+++ b/tests/accessibility/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 The Android Open Source Project
+# 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.
@@ -18,14 +18,21 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := CtsSomeAccessibilityServices
+LOCAL_PACKAGE_NAME := CtsAccessibilityTestCases
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 LOCAL_SDK_VERSION := current
 
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+include $(BUILD_CTS_PACKAGE)
 
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tests/accessibility/AndroidManifest.xml b/tests/accessibility/AndroidManifest.xml
index dde1de8..69c6479 100644
--- a/tests/accessibility/AndroidManifest.xml
+++ b/tests/accessibility/AndroidManifest.xml
@@ -17,30 +17,19 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.view.accessibility.services">
+          package="android.view.accessibility.cts">
 
-  <application>
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
 
-    <service android:name=".SpeakingAccessibilityService"
-             android:label="@string/title_speaking_accessibility_service"
-             android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
-      <intent-filter>
-        <action android:name="android.accessibilityservice.AccessibilityService"/>
-      </intent-filter>
-      <meta-data android:name="android.accessibilityservice"
-                android:resource="@xml/speaking_accessibilityservice" />
-    </service>
+    <application android:theme="@android:style/Theme.Holo.NoActionBar" >
+        <uses-library android:name="android.test.runner"/>
+    </application>
 
-    <service android:name=".VibratingAccessibilityService"
-             android:label="@string/title_vibrating_accessibility_service"
-             android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
-      <intent-filter>
-        <action android:name="android.accessibilityservice.AccessibilityService"/>
-      </intent-filter>
-      <meta-data android:name="android.accessibilityservice"
-                android:resource="@xml/vibrating_accessibilityservice" />
-    </service>
-
-  </application>
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.view.accessibility.cts"
+                     android:label="Tests for the accessibility APIs.">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
 
 </manifest>
diff --git a/tests/accessibility/AndroidTest.xml b/tests/accessibility/AndroidTest.xml
new file mode 100644
index 0000000..7c7c480
--- /dev/null
+++ b/tests/accessibility/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Accessibility test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAccessibilityTestCases.apk" />
+        <option name="test-file-name" value="CtsSomeAccessibilityServices.apk" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer" >
+        <option name="run-command" value="settings --user cur put secure enabled_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
+        <option name="run-command" value="settings --user cur put secure touch_exploration_granted_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
+        <option name="run-command" value="settings --user cur put secure accessibility_enabled 1" />
+        <option name="teardown-command" value="settings --user cur put secure enabled_accessibility_services &quot;&quot;" />
+        <option name="teardown-command" value="settings --user cur put secure touch_exploration_granted_accessibility_services &quot;&quot;" />
+        <option name="teardown-command" value="settings --user cur put secure accessibility_enabled 0" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.view.accessibility.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/accessibility/OldAndroidTest.xml b/tests/accessibility/OldAndroidTest.xml
new file mode 100644
index 0000000..d127319
--- /dev/null
+++ b/tests/accessibility/OldAndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Base config for CTS package preparer">
+    <include name="common-config" />
+    <option name="run-command:run-command" value="settings --user cur put secure enabled_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
+    <option name="run-command:run-command" value="settings --user cur put secure touch_exploration_granted_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
+    <option name="run-command:run-command" value="settings --user cur put secure accessibility_enabled 1" />
+    <option name="run-command:teardown-command" value="settings --user cur put secure enabled_accessibility_services &quot;&quot;" />
+    <option name="run-command:teardown-command" value="settings --user cur put secure touch_exploration_granted_accessibility_services &quot;&quot;" />
+    <option name="run-command:teardown-command" value="settings --user cur put secure accessibility_enabled 0" />
+    <option name="cts-apk-installer:test-file-name" value="CtsSomeAccessibilityServices.apk" />
+</configuration>
diff --git a/tests/tests/accessibility/res/values/ids.xml b/tests/accessibility/res/values/ids.xml
similarity index 100%
rename from tests/tests/accessibility/res/values/ids.xml
rename to tests/accessibility/res/values/ids.xml
diff --git a/tests/accessibility/service/Android.mk b/tests/accessibility/service/Android.mk
new file mode 100644
index 0000000..b0ba086
--- /dev/null
+++ b/tests/accessibility/service/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsSomeAccessibilityServices
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/accessibility/service/AndroidManifest.xml b/tests/accessibility/service/AndroidManifest.xml
new file mode 100644
index 0000000..dde1de8
--- /dev/null
+++ b/tests/accessibility/service/AndroidManifest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.view.accessibility.services">
+
+  <application>
+
+    <service android:name=".SpeakingAccessibilityService"
+             android:label="@string/title_speaking_accessibility_service"
+             android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+      <intent-filter>
+        <action android:name="android.accessibilityservice.AccessibilityService"/>
+      </intent-filter>
+      <meta-data android:name="android.accessibilityservice"
+                android:resource="@xml/speaking_accessibilityservice" />
+    </service>
+
+    <service android:name=".VibratingAccessibilityService"
+             android:label="@string/title_vibrating_accessibility_service"
+             android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+      <intent-filter>
+        <action android:name="android.accessibilityservice.AccessibilityService"/>
+      </intent-filter>
+      <meta-data android:name="android.accessibilityservice"
+                android:resource="@xml/vibrating_accessibilityservice" />
+    </service>
+
+  </application>
+
+</manifest>
diff --git a/tests/accessibility/res/values/strings.xml b/tests/accessibility/service/res/values/strings.xml
similarity index 100%
rename from tests/accessibility/res/values/strings.xml
rename to tests/accessibility/service/res/values/strings.xml
diff --git a/tests/accessibility/res/xml/speaking_accessibilityservice.xml b/tests/accessibility/service/res/xml/speaking_accessibilityservice.xml
similarity index 100%
rename from tests/accessibility/res/xml/speaking_accessibilityservice.xml
rename to tests/accessibility/service/res/xml/speaking_accessibilityservice.xml
diff --git a/tests/accessibility/res/xml/vibrating_accessibilityservice.xml b/tests/accessibility/service/res/xml/vibrating_accessibilityservice.xml
similarity index 100%
rename from tests/accessibility/res/xml/vibrating_accessibilityservice.xml
rename to tests/accessibility/service/res/xml/vibrating_accessibilityservice.xml
diff --git a/tests/accessibility/src/android/view/accessibility/services/SpeakingAccessibilityService.java b/tests/accessibility/service/src/android/view/accessibility/services/SpeakingAccessibilityService.java
similarity index 100%
rename from tests/accessibility/src/android/view/accessibility/services/SpeakingAccessibilityService.java
rename to tests/accessibility/service/src/android/view/accessibility/services/SpeakingAccessibilityService.java
diff --git a/tests/accessibility/src/android/view/accessibility/services/VibratingAccessibilityService.java b/tests/accessibility/service/src/android/view/accessibility/services/VibratingAccessibilityService.java
similarity index 100%
rename from tests/accessibility/src/android/view/accessibility/services/VibratingAccessibilityService.java
rename to tests/accessibility/service/src/android/view/accessibility/services/VibratingAccessibilityService.java
diff --git a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
similarity index 100%
rename from tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
rename to tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
diff --git a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
similarity index 100%
rename from tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
rename to tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
new file mode 100644
index 0000000..30847a5
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -0,0 +1,297 @@
+/*
+ * 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 android.view.accessibility.cts;
+
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.view.accessibility.cts.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class for testing {@link AccessibilityNodeInfo}.
+ */
+public class AccessibilityNodeInfoTest extends AndroidTestCase {
+
+    /** The number of properties of the {@link AccessibilityNodeInfo} class. */
+    private static final int NON_STATIC_FIELD_COUNT = 30;
+
+    @SmallTest
+    public void testMarshaling() throws Exception {
+        // no new fields, so we are testing marshaling of all such
+        AccessibilityRecordTest.assertNoNewNonStaticFieldsAdded(AccessibilityNodeInfo.class,
+                NON_STATIC_FIELD_COUNT);
+
+        // fully populate the node info to marshal
+        AccessibilityNodeInfo sentInfo = AccessibilityNodeInfo.obtain(new View(getContext()));
+        fullyPopulateAccessibilityNodeInfo(sentInfo);
+
+        // marshal and unmarshal the node info
+        Parcel parcel = Parcel.obtain();
+        sentInfo.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        AccessibilityNodeInfo receivedInfo = AccessibilityNodeInfo.CREATOR.createFromParcel(parcel);
+
+        // make sure all fields properly marshaled
+        assertEqualsAccessibilityNodeInfo(sentInfo, receivedInfo);
+    }
+
+    /**
+     * Tests if {@link AccessibilityNodeInfo}s are properly reused.
+     */
+    @SmallTest
+    public void testReuse() {
+        AccessibilityEvent firstInfo = AccessibilityEvent.obtain();
+        firstInfo.recycle();
+        AccessibilityEvent secondInfo = AccessibilityEvent.obtain();
+        assertSame("AccessibilityNodeInfo not properly reused", firstInfo, secondInfo);
+    }
+
+    /**
+     * Tests if {@link AccessibilityNodeInfo} are properly recycled.
+     */
+    @SmallTest
+    public void testRecycle() {
+        // obtain and populate an node info
+        AccessibilityNodeInfo populatedInfo = AccessibilityNodeInfo.obtain();
+        fullyPopulateAccessibilityNodeInfo(populatedInfo);
+
+        // recycle and obtain the same recycled instance
+        populatedInfo.recycle();
+        AccessibilityNodeInfo recycledInfo = AccessibilityNodeInfo.obtain();
+
+        // check expectations
+        assertAccessibilityNodeInfoCleared(recycledInfo);
+    }
+
+    /**
+     * Tests whether the event describes its contents consistently.
+     */
+    @SmallTest
+    public void testDescribeContents() {
+        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+        assertSame("Accessibility node infos always return 0 for this method.", 0,
+                info.describeContents());
+        fullyPopulateAccessibilityNodeInfo(info);
+        assertSame("Accessibility node infos always return 0 for this method.", 0,
+                info.describeContents());
+    }
+
+    /**
+     * Tests whether accessibility actions are properly added.
+     */
+    @SmallTest
+    public void testAddActions() {
+        List<AccessibilityAction> customActions = new ArrayList<AccessibilityAction>();
+        customActions.add(new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS, "Foo"));
+        customActions.add(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
+
+        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
+        info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
+        for (AccessibilityAction customAction : customActions) {
+            info.addAction(customAction);
+        }
+
+        assertSame(info.getActions(), (AccessibilityNodeInfo.ACTION_FOCUS
+                | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS));
+
+        List<AccessibilityAction> allActions = new ArrayList<AccessibilityAction>();
+        allActions.add(AccessibilityAction.ACTION_CLEAR_FOCUS);
+        allActions.addAll(customActions);
+        assertEquals(info.getActionList(), allActions);
+    }
+
+    /**
+     * Tests whether we catch addition of an action with invalid id.
+     */
+    @SmallTest
+    public void testCreateInvalidActionId() {
+        try {
+            new AccessibilityAction(3, null);
+        } catch (IllegalArgumentException iae) {
+            /* expected */
+        }
+    }
+
+    /**
+     * Tests whether accessibility actions are properly removed.
+     */
+    @SmallTest
+    public void testRemoveActions() {
+        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+
+        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
+        assertSame(info.getActions(), AccessibilityNodeInfo.ACTION_FOCUS);
+
+        info.removeAction(AccessibilityNodeInfo.ACTION_FOCUS);
+        assertSame(info.getActions(), 0);
+        assertTrue(info.getActionList().isEmpty());
+
+        AccessibilityAction customFocus = new AccessibilityAction(
+                AccessibilityNodeInfo.ACTION_FOCUS, "Foo");
+        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
+        info.addAction(customFocus);
+        assertSame(info.getActionList().size(), 1);
+        assertEquals(info.getActionList().get(0), customFocus);
+        assertSame(info.getActions(), AccessibilityNodeInfo.ACTION_FOCUS);
+
+        info.removeAction(customFocus);
+        assertSame(info.getActions(), 0);
+        assertTrue(info.getActionList().isEmpty());
+    }
+
+    /**
+     * Fully populates the {@link AccessibilityNodeInfo} to marshal.
+     *
+     * @param info The node info to populate.
+     */
+    private void fullyPopulateAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        info.setParent(new View(getContext()));
+        info.setSource(new View(getContext()));
+        info.addChild(new View(getContext()));
+        info.addChild(new View(getContext()), 1);
+        info.setBoundsInParent(new Rect(1,1,1,1));
+        info.setBoundsInScreen(new Rect(2,2,2,2));
+        info.setClassName("foo.bar.baz.Class");
+        info.setContentDescription("content description");
+        info.setPackageName("foo.bar.baz");
+        info.setText("text");
+        info.setCheckable(true);
+        info.setChecked(true);
+        info.setClickable(true);
+        info.setEnabled(true);
+        info.setFocusable(true);
+        info.setFocused(true);
+        info.setLongClickable(true);
+        info.setContextClickable(true);
+        info.setPassword(true);
+        info.setScrollable(true);
+        info.setSelected(true);
+        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
+        info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
+        info.addAction(new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS, "Foo"));
+        info.addAction(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
+        info.setAccessibilityFocused(true);
+        info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+        info.setLabeledBy(new View(getContext()));
+        info.setLabelFor(new View(getContext()));
+        info.setViewIdResourceName("foo.bar:id/baz");
+    }
+
+    /**
+     * Compares all properties of the <code>expectedInfo</code> and the
+     * <code>receviedInfo</code> to verify that the received node info is
+     * the one that is expected.
+     */
+    public static void assertEqualsAccessibilityNodeInfo(AccessibilityNodeInfo expectedInfo,
+            AccessibilityNodeInfo receivedInfo) {
+        Rect expectedBounds = new Rect();
+        Rect receivedBounds = new Rect();
+        expectedInfo.getBoundsInParent(expectedBounds);
+        receivedInfo.getBoundsInParent(receivedBounds);
+        assertEquals("boundsInParent has incorrect value", expectedBounds, receivedBounds);
+        expectedInfo.getBoundsInScreen(expectedBounds);
+        receivedInfo.getBoundsInScreen(receivedBounds);
+        assertEquals("boundsInScreen has incorrect value", expectedBounds, receivedBounds);
+        assertEquals("className has incorrect value", expectedInfo.getClassName(),
+                receivedInfo.getClassName());
+        assertEquals("contentDescription has incorrect value", expectedInfo.getContentDescription(),
+                receivedInfo.getContentDescription());
+        assertEquals("packageName has incorrect value", expectedInfo.getPackageName(),
+                receivedInfo.getPackageName());
+        assertEquals("text has incorrect value", expectedInfo.getText(), receivedInfo.getText());
+        assertSame("checkable has incorrect value", expectedInfo.isCheckable(),
+                receivedInfo.isCheckable());
+        assertSame("checked has incorrect value", expectedInfo.isChecked(),
+                receivedInfo.isChecked());
+        assertSame("clickable has incorrect value", expectedInfo.isClickable(),
+                receivedInfo.isClickable());
+        assertSame("enabled has incorrect value", expectedInfo.isEnabled(),
+                receivedInfo.isEnabled());
+        assertSame("focusable has incorrect value", expectedInfo.isFocusable(),
+                receivedInfo.isFocusable());
+        assertSame("focused has incorrect value", expectedInfo.isFocused(),
+                receivedInfo.isFocused());
+        assertSame("longClickable has incorrect value", expectedInfo.isLongClickable(),
+                receivedInfo.isLongClickable());
+        assertSame("contextClickable has incorrect value", expectedInfo.isContextClickable(),
+                receivedInfo.isContextClickable());
+        assertSame("password has incorrect value", expectedInfo.isPassword(),
+                receivedInfo.isPassword());
+        assertSame("scrollable has incorrect value", expectedInfo.isScrollable(),
+                receivedInfo.isScrollable());
+        assertSame("selected has incorrect value", expectedInfo.isSelected(),
+                receivedInfo.isSelected());
+        assertSame("actions has incorrect value", expectedInfo.getActions(),
+                receivedInfo.getActions());
+        assertEquals("actionsSet has incorrect value", expectedInfo.getActionList(),
+                receivedInfo.getActionList());
+        assertSame("childCount has incorrect value", expectedInfo.getChildCount(),
+                receivedInfo.getChildCount());
+        assertSame("childCount has incorrect value", expectedInfo.getChildCount(),
+                receivedInfo.getChildCount());
+        assertSame("accessibilityFocused has incorrect value",
+                expectedInfo.isAccessibilityFocused(),
+                receivedInfo.isAccessibilityFocused());
+        assertSame("movementGranularities has incorrect value",
+                expectedInfo.getMovementGranularities(),
+                receivedInfo.getMovementGranularities());
+        assertEquals("viewId has incorrect value", expectedInfo.getViewIdResourceName(),
+                receivedInfo.getViewIdResourceName());
+    }
+
+    /**
+     * Asserts that an {@link AccessibilityNodeInfo} is cleared.
+     *
+     * @param info The node info to check.
+     */
+    public static void assertAccessibilityNodeInfoCleared(AccessibilityNodeInfo info) {
+        Rect bounds = new Rect();
+        info.getBoundsInParent(bounds);
+        assertTrue("boundsInParent not properly recycled", bounds.isEmpty());
+        info.getBoundsInScreen(bounds);
+        assertTrue("boundsInScreen not properly recycled", bounds.isEmpty());
+        assertNull("className not properly recycled", info.getClassName());
+        assertNull("contentDescription not properly recycled", info.getContentDescription());
+        assertNull("packageName not properly recycled", info.getPackageName());
+        assertNull("text not properly recycled", info.getText());
+        assertFalse("checkable not properly recycled", info.isCheckable());
+        assertFalse("checked not properly recycled", info.isChecked());
+        assertFalse("clickable not properly recycled", info.isClickable());
+        assertFalse("enabled not properly recycled", info.isEnabled());
+        assertFalse("focusable not properly recycled", info.isFocusable());
+        assertFalse("focused not properly recycled", info.isFocused());
+        assertFalse("longClickable not properly recycled", info.isLongClickable());
+        assertFalse("contextClickable not properly recycled", info.isContextClickable());
+        assertFalse("password not properly recycled", info.isPassword());
+        assertFalse("scrollable not properly recycled", info.isScrollable());
+        assertFalse("selected not properly recycled", info.isSelected());
+        assertSame("actions not properly recycled", 0, info.getActions());
+        assertFalse("accessibilityFocused not properly recycled", info.isAccessibilityFocused());
+        assertSame("movementGranularities not properly recycled", 0,
+                info.getMovementGranularities());
+        assertNull("viewId not properly recycled", info.getViewIdResourceName());
+    }
+}
diff --git a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
similarity index 100%
rename from tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
rename to tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
diff --git a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
similarity index 100%
rename from tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
rename to tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
diff --git a/tests/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
similarity index 100%
rename from tests/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
rename to tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
diff --git a/tests/accessibilityservice/Android.mk b/tests/accessibilityservice/Android.mk
new file mode 100644
index 0000000..6d757e1
--- /dev/null
+++ b/tests/accessibilityservice/Android.mk
@@ -0,0 +1,32 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_PACKAGE_NAME := CtsAccessibilityServiceTestCases
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
new file mode 100644
index 0000000..f93e441
--- /dev/null
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -0,0 +1,52 @@
+<?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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.accessibilityservice.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+
+    <application android:theme="@android:style/Theme.Holo.NoActionBar" >
+
+      <uses-library android:name="android.test.runner"/>
+
+      <activity android:label="@string/accessibility_end_to_end_test_activity"
+              android:name=".AccessibilityEndToEndActivity"/>
+
+      <activity android:label="@string/accessibility_query_window_test_activity"
+              android:name=".AccessibilityWindowQueryActivity"/>
+
+      <activity android:label="@string/accessibility_view_tree_reporting_test_activity"
+              android:name=".AccessibilityViewTreeReportingActivity"/>
+
+      <activity android:label="@string/accessibility_focus_and_input_focus_sync_test_activity"
+              android:name=".AccessibilityFocusAndInputFocusSyncActivity"/>
+
+      <activity android:label="@string/accessibility_text_traversal_test_activity"
+              android:name=".AccessibilityTextTraversalActivity"/>
+
+  </application>
+
+  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                   android:targetPackage="android.accessibilityservice.cts"
+                   android:label="Tests for the accessibility APIs.">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/accessibilityservice/AndroidTest.xml b/tests/accessibilityservice/AndroidTest.xml
new file mode 100644
index 0000000..db2707d
--- /dev/null
+++ b/tests/accessibilityservice/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Accessibility test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAccessibilityServiceTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.accessibilityservice.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/accessibilityservice/res/layout/accessibility_focus_and_input_focus_sync_test.xml b/tests/accessibilityservice/res/layout/accessibility_focus_and_input_focus_sync_test.xml
similarity index 100%
rename from tests/tests/accessibilityservice/res/layout/accessibility_focus_and_input_focus_sync_test.xml
rename to tests/accessibilityservice/res/layout/accessibility_focus_and_input_focus_sync_test.xml
diff --git a/tests/tests/accessibilityservice/res/layout/accessibility_text_traversal_test.xml b/tests/accessibilityservice/res/layout/accessibility_text_traversal_test.xml
similarity index 100%
rename from tests/tests/accessibilityservice/res/layout/accessibility_text_traversal_test.xml
rename to tests/accessibilityservice/res/layout/accessibility_text_traversal_test.xml
diff --git a/tests/tests/accessibilityservice/res/layout/accessibility_view_tree_reporting_test.xml b/tests/accessibilityservice/res/layout/accessibility_view_tree_reporting_test.xml
similarity index 100%
rename from tests/tests/accessibilityservice/res/layout/accessibility_view_tree_reporting_test.xml
rename to tests/accessibilityservice/res/layout/accessibility_view_tree_reporting_test.xml
diff --git a/tests/tests/accessibilityservice/res/layout/end_to_end_test.xml b/tests/accessibilityservice/res/layout/end_to_end_test.xml
similarity index 100%
rename from tests/tests/accessibilityservice/res/layout/end_to_end_test.xml
rename to tests/accessibilityservice/res/layout/end_to_end_test.xml
diff --git a/tests/tests/accessibilityservice/res/layout/list_view_row.xml b/tests/accessibilityservice/res/layout/list_view_row.xml
similarity index 100%
rename from tests/tests/accessibilityservice/res/layout/list_view_row.xml
rename to tests/accessibilityservice/res/layout/list_view_row.xml
diff --git a/tests/tests/accessibilityservice/res/layout/query_window_test.xml b/tests/accessibilityservice/res/layout/query_window_test.xml
similarity index 100%
rename from tests/tests/accessibilityservice/res/layout/query_window_test.xml
rename to tests/accessibilityservice/res/layout/query_window_test.xml
diff --git a/tests/tests/accessibilityservice/res/values/ids.xml b/tests/accessibilityservice/res/values/ids.xml
similarity index 100%
rename from tests/tests/accessibilityservice/res/values/ids.xml
rename to tests/accessibilityservice/res/values/ids.xml
diff --git a/tests/tests/accessibilityservice/res/values/strings.xml b/tests/accessibilityservice/res/values/strings.xml
similarity index 100%
rename from tests/tests/accessibilityservice/res/values/strings.xml
rename to tests/accessibilityservice/res/values/strings.xml
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java
similarity index 100%
rename from tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java
rename to tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndActivity.java
new file mode 100644
index 0000000..9a26ac7
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndActivity.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.accessibilityservice.cts.R;
+
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+/**
+ * This class is an {@link android.app.Activity} used to perform end-to-end
+ * testing of the accessibility feature by interaction with the
+ * UI widgets.
+ */
+public class AccessibilityEndToEndActivity extends AccessibilityTestActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.end_to_end_test);
+
+        ListAdapter listAdapter = new BaseAdapter() {
+            public View getView(int position, View convertView, ViewGroup parent) {
+                TextView textView = (TextView) View
+                        .inflate(AccessibilityEndToEndActivity.this, R.layout.list_view_row, null);
+                textView.setText((String) getItem(position));
+                return textView;
+            }
+
+            public long getItemId(int position) {
+                return position;
+            }
+
+            public Object getItem(int position) {
+                if (position == 0) {
+                    return AccessibilityEndToEndActivity.this.getString(R.string.first_list_item);
+                } else {
+                    return AccessibilityEndToEndActivity.this.getString(R.string.second_list_item);
+                }
+            }
+
+            public int getCount() {
+                return 2;
+            }
+        };
+
+        ListView listView = (ListView) findViewById(R.id.listview);
+        listView.setAdapter(listAdapter);
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
new file mode 100644
index 0000000..1bd4e0a
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -0,0 +1,437 @@
+/*
+ * 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.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.app.UiAutomation;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ListView;
+
+import android.accessibilityservice.cts.R;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This class performs end-to-end testing of the accessibility feature by
+ * creating an {@link Activity} and poking around so {@link AccessibilityEvent}s
+ * are generated and their correct dispatch verified.
+ */
+public class AccessibilityEndToEndTest extends
+        AccessibilityActivityTestCase<AccessibilityEndToEndActivity> {
+
+    private static final String LOG_TAG = "AccessibilityEndToEndTest";
+
+    /**
+     * Creates a new instance for testing {@link AccessibilityEndToEndActivity}.
+     */
+    public AccessibilityEndToEndTest() {
+        super(AccessibilityEndToEndActivity.class);
+    }
+
+    @MediumTest
+    public void testTypeViewSelectedAccessibilityEvent() throws Throwable {
+        // create and populate the expected event
+        final AccessibilityEvent expected = AccessibilityEvent.obtain();
+        expected.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED);
+        expected.setClassName(ListView.class.getName());
+        expected.setPackageName(getActivity().getPackageName());
+        expected.getText().add(getActivity().getString(R.string.second_list_item));
+        expected.setItemCount(2);
+        expected.setCurrentItemIndex(1);
+        expected.setEnabled(true);
+        expected.setScrollable(false);
+        expected.setFromIndex(0);
+        expected.setToIndex(1);
+
+        final ListView listView = (ListView) getActivity().findViewById(R.id.listview);
+
+        AccessibilityEvent awaitedEvent =
+            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+                new Runnable() {
+            @Override
+            public void run() {
+                // trigger the event
+                getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        listView.setSelection(1);
+                    }
+                });
+            }},
+            new UiAutomation.AccessibilityEventFilter() {
+                // check the received event
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return equalsAccessiblityEvent(event, expected);
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
+    }
+
+    @MediumTest
+    public void testTypeViewClickedAccessibilityEvent() throws Throwable {
+        // create and populate the expected event
+        final AccessibilityEvent expected = AccessibilityEvent.obtain();
+        expected.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
+        expected.setClassName(Button.class.getName());
+        expected.setPackageName(getActivity().getPackageName());
+        expected.getText().add(getActivity().getString(R.string.button_title));
+        expected.setEnabled(true);
+
+        final Button button = (Button) getActivity().findViewById(R.id.button);
+
+        AccessibilityEvent awaitedEvent =
+            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+                new Runnable() {
+            @Override
+            public void run() {
+                // trigger the event
+                getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        button.performClick();
+                    }
+                });
+            }},
+            new UiAutomation.AccessibilityEventFilter() {
+                // check the received event
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return equalsAccessiblityEvent(event, expected);
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
+    }
+
+    @MediumTest
+    public void testTypeViewLongClickedAccessibilityEvent() throws Throwable {
+        // create and populate the expected event
+        final AccessibilityEvent expected = AccessibilityEvent.obtain();
+        expected.setEventType(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
+        expected.setClassName(Button.class.getName());
+        expected.setPackageName(getActivity().getPackageName());
+        expected.getText().add(getActivity().getString(R.string.button_title));
+        expected.setEnabled(true);
+
+        final Button button = (Button) getActivity().findViewById(R.id.button);
+
+        AccessibilityEvent awaitedEvent =
+            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+                new Runnable() {
+            @Override
+            public void run() {
+                // trigger the event
+                getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        button.performLongClick();
+                    }
+                });
+            }},
+            new UiAutomation.AccessibilityEventFilter() {
+                // check the received event
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return equalsAccessiblityEvent(event, expected);
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
+    }
+
+    @MediumTest
+    public void testTypeViewFocusedAccessibilityEvent() throws Throwable {
+        // create and populate the expected event
+        final AccessibilityEvent expected = AccessibilityEvent.obtain();
+        expected.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        expected.setClassName(Button.class.getName());
+        expected.setPackageName(getActivity().getPackageName());
+        expected.getText().add(getActivity().getString(R.string.button_title));
+        expected.setItemCount(3);
+        expected.setCurrentItemIndex(2);
+        expected.setEnabled(true);
+
+        final Button button = (Button) getActivity().findViewById(R.id.button);
+
+        AccessibilityEvent awaitedEvent =
+            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+                new Runnable() {
+            @Override
+            public void run() {
+                // trigger the event
+                getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        button.requestFocus();
+                    }
+                });
+            }},
+            new UiAutomation.AccessibilityEventFilter() {
+                // check the received event
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return equalsAccessiblityEvent(event, expected);
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
+    }
+
+    @MediumTest
+    public void testTypeViewTextChangedAccessibilityEvent() throws Throwable {
+        // focus the edit text
+        final EditText editText = (EditText) getActivity().findViewById(R.id.edittext);
+
+        AccessibilityEvent awaitedFocusEvent =
+            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+                new Runnable() {
+            @Override
+            public void run() {
+                // trigger the event
+                getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        editText.requestFocus();
+                    }
+                });
+            }},
+            new UiAutomation.AccessibilityEventFilter() {
+                // check the received event
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED;
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+        assertNotNull("Did not receive expected focuss event.", awaitedFocusEvent);
+
+        final String beforeText = getActivity().getString(R.string.text_input_blah);
+        final String newText = getActivity().getString(R.string.text_input_blah_blah);
+        final String afterText = beforeText.substring(0, 3) + newText;
+
+        // create and populate the expected event
+        final AccessibilityEvent expected = AccessibilityEvent.obtain();
+        expected.setEventType(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+        expected.setClassName(EditText.class.getName());
+        expected.setPackageName(getActivity().getPackageName());
+        expected.getText().add(afterText);
+        expected.setBeforeText(beforeText);
+        expected.setFromIndex(3);
+        expected.setAddedCount(9);
+        expected.setRemovedCount(1);
+        expected.setEnabled(true);
+
+        AccessibilityEvent awaitedTextChangeEvent =
+            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+                new Runnable() {
+            @Override
+            public void run() {
+                // trigger the event
+                getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        editText.getEditableText().replace(3, 4, newText);
+                    }
+                });
+            }},
+            new UiAutomation.AccessibilityEventFilter() {
+                // check the received event
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return equalsAccessiblityEvent(event, expected);
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+        assertNotNull("Did not receive expected event: " + expected, awaitedTextChangeEvent);
+    }
+
+    @MediumTest
+    public void testTypeWindowStateChangedAccessibilityEvent() throws Throwable {
+        // create and populate the expected event
+        final AccessibilityEvent expected = AccessibilityEvent.obtain();
+        expected.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        expected.setClassName(AlertDialog.class.getName());
+        expected.setPackageName(getActivity().getPackageName());
+        expected.getText().add(getActivity().getString(R.string.alert_title));
+        expected.getText().add(getActivity().getString(R.string.alert_message));
+        expected.setEnabled(true);
+
+        AccessibilityEvent awaitedEvent =
+            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+                new Runnable() {
+            @Override
+            public void run() {
+                // trigger the event
+                getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        (new AlertDialog.Builder(getActivity()).setTitle(R.string.alert_title)
+                                .setMessage(R.string.alert_message)).create().show();
+                    }
+                });
+            }},
+            new UiAutomation.AccessibilityEventFilter() {
+                // check the received event
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return equalsAccessiblityEvent(event, expected);
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
+    }
+
+    @MediumTest
+    @SuppressWarnings("deprecation")
+    public void testTypeNotificationStateChangedAccessibilityEvent() throws Throwable {
+        // No notification UI on televisions.
+        if((getActivity().getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) {
+            Log.i(LOG_TAG, "Skipping: testTypeNotificationStateChangedAccessibilityEvent" +
+                    " - No notification UI on televisions.");
+            return;
+        }
+
+        String message = getActivity().getString(R.string.notification_message);
+
+        // create the notification to send
+        final int notificationId = 1;
+        final Notification notification = new Notification.Builder(getActivity())
+                .setSmallIcon(android.R.drawable.stat_notify_call_mute)
+                .setContentIntent(PendingIntent.getActivity(getActivity(), 0, new Intent(),
+                        PendingIntent.FLAG_CANCEL_CURRENT))
+                .setTicker(message)
+                .setContentTitle("")
+                .setContentText("")
+                // Mark the notification as "interruptive" by specifying a vibration pattern. This
+                // ensures it's announced properly on watch-type devices.
+                .setVibrate(new long[] {})
+                .build();
+
+        // create and populate the expected event
+        final AccessibilityEvent expected = AccessibilityEvent.obtain();
+        expected.setEventType(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
+        expected.setClassName(Notification.class.getName());
+        expected.setPackageName(getActivity().getPackageName());
+        expected.getText().add(message);
+        expected.setParcelableData(notification);
+
+        AccessibilityEvent awaitedEvent =
+            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+                new Runnable() {
+            @Override
+            public void run() {
+                // trigger the event
+                getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        // trigger the event
+                        NotificationManager notificationManager =
+                            (NotificationManager) getActivity().getSystemService(
+                                    Service.NOTIFICATION_SERVICE);
+                        notificationManager.notify(notificationId, notification);
+                        getActivity().finish();
+                    }
+                });
+            }},
+            new UiAutomation.AccessibilityEventFilter() {
+                // check the received event
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return equalsAccessiblityEvent(event, expected);
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
+    }
+
+    /**
+     * Compares all properties of the <code>first</code> and the
+     * <code>second</code>.
+     */
+    private boolean equalsAccessiblityEvent(AccessibilityEvent first, AccessibilityEvent second) {
+         return first.getEventType() == second.getEventType()
+            && first.isChecked() == second.isChecked()
+            && first.getCurrentItemIndex() == second.getCurrentItemIndex()
+            && first.isEnabled() == second.isEnabled()
+            && first.getFromIndex() == second.getFromIndex()
+            && first.getItemCount() == second.getItemCount()
+            && first.isPassword() == second.isPassword()
+            && first.getRemovedCount() == second.getRemovedCount()
+            && first.isScrollable()== second.isScrollable()
+            && first.getToIndex() == second.getToIndex()
+            && first.getRecordCount() == second.getRecordCount()
+            && first.getScrollX() == second.getScrollX()
+            && first.getScrollY() == second.getScrollY()
+            && first.getAddedCount() == second.getAddedCount()
+            && TextUtils.equals(first.getBeforeText(), second.getBeforeText())
+            && TextUtils.equals(first.getClassName(), second.getClassName())
+            && TextUtils.equals(first.getContentDescription(), second.getContentDescription())
+            && equalsNotificationAsParcelableData(first, second)
+            && equalsText(first, second);
+    }
+
+    /**
+     * Compares the {@link android.os.Parcelable} data of the
+     * <code>first</code> and <code>second</code>.
+     */
+    private boolean equalsNotificationAsParcelableData(AccessibilityEvent first,
+            AccessibilityEvent second) {
+        Notification firstNotification = (Notification) first.getParcelableData();
+        Notification secondNotification = (Notification) second.getParcelableData();
+        if (firstNotification == null) {
+            return (secondNotification == null);
+        } else if (secondNotification == null) {
+            return false;
+        }
+        return TextUtils.equals(firstNotification.tickerText, secondNotification.tickerText);
+    }
+
+    /**
+     * Compares the text of the <code>first</code> and <code>second</code> text.
+     */
+    private boolean equalsText(AccessibilityEvent first, AccessibilityEvent second) {
+        List<CharSequence> firstText = first.getText();
+        List<CharSequence> secondText = second.getText();
+        if (firstText.size() != secondText.size()) {
+            return false;
+        }
+        Iterator<CharSequence> firstIterator = firstText.iterator();
+        Iterator<CharSequence> secondIterator = secondText.iterator();
+        for (int i = 0; i < firstText.size(); i++) {
+            if (!firstIterator.next().toString().equals(secondIterator.next().toString())) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncActivity.java
new file mode 100644
index 0000000..62831a4
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncActivity.java
@@ -0,0 +1,35 @@
+/**
+ * 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 android.accessibilityservice.cts;
+
+import android.os.Bundle;
+
+import android.accessibilityservice.cts.R;
+
+/**
+ * Activity for testing the accessibility focus APIs exposed to
+ * accessibility services. These APIs allow moving accessibility
+ * focus in the view tree from an AccessiiblityService. Specifically,
+ * this activity is for verifying the the sync between accessibility
+ * and input focus.
+ */
+public class AccessibilityFocusAndInputFocusSyncActivity extends AccessibilityTestActivity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.accessibility_focus_and_input_focus_sync_test);
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
new file mode 100644
index 0000000..ec420de
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
@@ -0,0 +1,229 @@
+/**
+ * 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 android.accessibilityservice.cts;
+
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+
+import android.app.UiAutomation;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import android.accessibilityservice.cts.R;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * Test cases for testing the accessibility focus APIs exposed to accessibility
+ * services. These APIs allow moving accessibility focus in the view tree from
+ * an AccessiiblityService. Specifically, this activity is for verifying the the
+ * sync between accessibility and input focus.
+ */
+public class AccessibilityFocusAndInputFocusSyncTest
+        extends AccessibilityActivityTestCase<AccessibilityFocusAndInputFocusSyncActivity>{
+
+    public AccessibilityFocusAndInputFocusSyncTest() {
+        super(AccessibilityFocusAndInputFocusSyncActivity.class);
+    }
+
+    @MediumTest
+    public void testFindAccessibilityFocus() throws Exception {
+        // Get the view that has input and accessibility focus.
+        final AccessibilityNodeInfo expected = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.firstEditText)).get(0);
+        assertNotNull(expected);
+        assertFalse(expected.isAccessibilityFocused());
+        assertTrue(expected.isFocused());
+
+        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                // Perform a focus action and check for success.
+                assertTrue(expected.performAction(ACTION_ACCESSIBILITY_FOCUS));
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Get the second expected node info.
+        AccessibilityNodeInfo received = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+        assertNotNull(received);
+        assertTrue(received.isAccessibilityFocused());
+
+        // Make sure we got the expected focusable.
+        assertEquals(expected, received);
+    }
+
+    @MediumTest
+    public void testInitialStateNoAccessibilityFocus() throws Exception {
+        // Get the root which is only accessibility focused.
+        AccessibilityNodeInfo focused = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+        assertNull(focused);
+    }
+
+    @MediumTest
+    public void testActionAccessibilityFocus() throws Exception {
+        // Get the root linear layout info.
+        final AccessibilityNodeInfo rootLinearLayout = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.rootLinearLayout)).get(0);
+        assertNotNull(rootLinearLayout);
+        assertFalse(rootLinearLayout.isAccessibilityFocused());
+
+        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                // Perform a focus action and check for success.
+                assertTrue(rootLinearLayout.performAction(ACTION_ACCESSIBILITY_FOCUS));
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Get the node info again.
+        rootLinearLayout.refresh();
+
+        // Check if the node info is focused.
+        assertTrue(rootLinearLayout.isAccessibilityFocused());
+    }
+
+    @MediumTest
+    public void testActionClearAccessibilityFocus() throws Exception {
+        // Get the root linear layout info.
+        final AccessibilityNodeInfo rootLinearLayout = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.rootLinearLayout)).get(0);
+        assertNotNull(rootLinearLayout);
+
+        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                // Perform a focus action and check for success.
+                assertTrue(rootLinearLayout.performAction(ACTION_ACCESSIBILITY_FOCUS));
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Refresh the node info.
+        rootLinearLayout.refresh();
+
+        // Check if the node info is focused.
+        assertTrue(rootLinearLayout.isAccessibilityFocused());
+
+        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                // Perform a clear focus action and check for success.
+                assertTrue(rootLinearLayout.performAction(ACTION_CLEAR_ACCESSIBILITY_FOCUS));
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return event.getEventType()
+                        == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Refresh the node info.
+        rootLinearLayout.refresh();
+
+        // Check if the node info is not focused.
+        assertFalse(rootLinearLayout.isAccessibilityFocused());
+    }
+
+    @MediumTest
+    public void testOnlyOneNodeHasAccessibilityFocus() throws Exception {
+        // Get the first not focused edit text.
+        final AccessibilityNodeInfo firstEditText = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.firstEditText)).get(0);
+        assertNotNull(firstEditText);
+        assertTrue(firstEditText.isFocusable());
+        assertTrue(firstEditText.isFocused());
+        assertFalse(firstEditText.isAccessibilityFocused());
+
+        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                // Perform a set focus action and check for success.
+                assertTrue(firstEditText.performAction(ACTION_ACCESSIBILITY_FOCUS));
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Get the second not focused edit text.
+        final AccessibilityNodeInfo secondEditText = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.secondEditText)).get(0);
+        assertNotNull(secondEditText);
+        assertTrue(secondEditText.isFocusable());
+        assertFalse(secondEditText.isFocused());
+        assertFalse(secondEditText.isAccessibilityFocused());
+
+        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                // Perform a set focus action and check for success.
+                assertTrue(secondEditText.performAction(ACTION_ACCESSIBILITY_FOCUS));
+                
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Get the node info again.
+        secondEditText.refresh();
+
+        // Make sure no other node has accessibility focus.
+        AccessibilityNodeInfo root = getInstrumentation().getUiAutomation().getRootInActiveWindow();
+        Queue<AccessibilityNodeInfo> workQueue = new LinkedList<AccessibilityNodeInfo>();
+        workQueue.add(root);
+        while (!workQueue.isEmpty()) {
+            AccessibilityNodeInfo current = workQueue.poll();
+            if (current.isAccessibilityFocused() && !current.equals(secondEditText)) {
+                fail();
+            }
+            final int childCount = current.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                AccessibilityNodeInfo child = current.getChild(i);
+                if (child != null) {
+                    workQueue.offer(child);
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
similarity index 100%
rename from tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
rename to tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java
similarity index 100%
rename from tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java
rename to tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTestActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTestActivity.java
similarity index 100%
rename from tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTestActivity.java
rename to tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTestActivity.java
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalActivity.java
new file mode 100644
index 0000000..2b93a08
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalActivity.java
@@ -0,0 +1,32 @@
+/**
+ * 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 android.accessibilityservice.cts;
+
+import android.os.Bundle;
+
+import android.accessibilityservice.cts.R;
+
+/**
+ * Activity for testing the accessibility APIs for traversing the
+ * text content of a View at several granularities.
+ */
+public class AccessibilityTextTraversalActivity extends AccessibilityTestActivity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.accessibility_text_traversal_test);
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
new file mode 100644
index 0000000..f5958f9
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
@@ -0,0 +1,4646 @@
+/**
+ * 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 android.accessibilityservice.cts;
+
+import android.app.UiAutomation;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.Selection;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import android.accessibilityservice.cts.R;
+
+/**
+ * Test cases for testing the accessibility APIs for traversing the text content of
+ * a View at several granularities.
+ */
+public class AccessibilityTextTraversalTest
+        extends AccessibilityActivityTestCase<AccessibilityTextTraversalActivity>{
+
+    public AccessibilityTextTraversalTest() {
+        super(AccessibilityTextTraversalActivity.class);
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityCharacterOverContentDescription()
+            throws Exception {
+        final View view = getActivity().findViewById(R.id.view);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                view.setVisibility(View.VISIBLE);
+                view.setContentDescription(getString(R.string.a_b));
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.a_b)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
+                        arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.a_b))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 1
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
+                        arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.a_b))
+                        && event.getFromIndex() == 1
+                        && event.getToIndex() == 2
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
+                        arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.a_b))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
+                arguments));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
+                        arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.a_b))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
+                        arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.a_b))
+                        && event.getFromIndex() == 1
+                        && event.getToIndex() == 2
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
+                        arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.a_b))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 1
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityWordOverContentDescription()
+            throws Exception {
+        final View view = getActivity().findViewById(R.id.view);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                view.setVisibility(View.VISIBLE);
+                view.setContentDescription(getString(R.string.foo_bar_baz));
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.foo_bar_baz)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 4
+                        && event.getToIndex() == 7
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 8
+                        && event.getToIndex() == 11
+                        && event.getMovementGranularity() ==
+                               AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 8
+                        && event.getToIndex() == 11
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 4
+                        && event.getToIndex() == 7
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(View.class.getName())
+                        && event.getContentDescription().toString().equals(
+                                getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityCharacterOverText()
+            throws Exception {
+        final TextView textView = (TextView) getActivity().findViewById(R.id.text);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setVisibility(View.VISIBLE);
+                textView.setText(getString(R.string.a_b));
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                       getString(R.string.a_b)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 1
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(1, Selection.getSelectionStart(textView.getText()));
+        assertEquals(1, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 1
+                        && event.getToIndex() == 2
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(textView.getText()));
+        assertEquals(2, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(textView.getText()));
+        assertEquals(3, Selection.getSelectionEnd(textView.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(textView.getText()));
+        assertEquals(3, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(textView.getText()));
+        assertEquals(2, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 1
+                        && event.getToIndex() == 2
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(1, Selection.getSelectionStart(textView.getText()));
+        assertEquals(1, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 1
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(seventhExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(textView.getText()));
+        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(textView.getText()));
+        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityCharacterOverTextExtend()
+            throws Exception {
+        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setVisibility(View.VISIBLE);
+                editText.setText(getString(R.string.a_b));
+                Selection.removeSelection(editText.getText());
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                       getString(R.string.a_b)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+        arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 1
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(1, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 1
+                        && event.getToIndex() == 2
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 1
+                        && event.getToIndex() == 2
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(1, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 1
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Focus the view so we can change selection.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setFocusable(true);
+                editText.requestFocus();
+            }
+        });
+
+        // Put selection at the end of the text.
+        Bundle setSelectionArgs = new Bundle();
+        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 3);
+        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 3);
+        assertTrue(text.performAction(
+                AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(editText.getText()));
+        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
+
+        // Unfocus the view so we can get rid of the soft-keyboard.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.clearFocus();
+                editText.setFocusable(false);
+            }
+        });
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(seventhExpected);
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(editText.getText()));
+        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent eightExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 1
+                        && event.getToIndex() == 2
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(eightExpected);
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(editText.getText()));
+        assertEquals(1, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent ninethExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 1
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(ninethExpected);
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent tenthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 1
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(tenthExpected);
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(editText.getText()));
+        assertEquals(1, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent eleventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 1
+                        && event.getToIndex() == 2
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(eleventhExpected);
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(editText.getText()));
+        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent twelvethExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(twelvethExpected);
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(editText.getText()));
+        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(editText.getText()));
+        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityWordOverText() throws Exception {
+        final TextView textView = (TextView) getActivity().findViewById(R.id.text);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setVisibility(View.VISIBLE);
+                textView.setText(getString(R.string.foo_bar_baz));
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                       R.string.foo_bar_baz)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(3, Selection.getSelectionStart(textView.getText()));
+        assertEquals(3, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 4
+                        && event.getToIndex() == 7
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(7, Selection.getSelectionStart(textView.getText()));
+        assertEquals(7, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 8
+                        && event.getToIndex() == 11
+                        && event.getMovementGranularity() ==
+                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(textView.getText()));
+        assertEquals(11, Selection.getSelectionEnd(textView.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(textView.getText()));
+        assertEquals(11, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 8
+                        && event.getToIndex() == 11
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Verify the selection position.
+        assertEquals(8, Selection.getSelectionStart(textView.getText()));
+        assertEquals(8, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 4
+                        && event.getToIndex() == 7
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(4, Selection.getSelectionStart(textView.getText()));
+        assertEquals(4, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(textView.getText()));
+        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(textView.getText()));
+        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityWordOverEditTextWithContentDescription()
+            throws Exception {
+        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setVisibility(View.VISIBLE);
+                editText.setText(getString(R.string.foo_bar_baz));
+                editText.setContentDescription(getString(R.string.android_wiki));
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                       R.string.foo_bar_baz)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getContentDescription().equals(getString(R.string.android_wiki))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(3, editText.getSelectionStart());
+        assertEquals(3, editText.getSelectionEnd());
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getContentDescription().equals(getString(R.string.android_wiki))
+                        && event.getFromIndex() == 4
+                        && event.getToIndex() == 7
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(7, editText.getSelectionStart());
+        assertEquals(7, editText.getSelectionEnd());
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getContentDescription().equals(getString(R.string.android_wiki))
+                        && event.getFromIndex() == 8
+                        && event.getToIndex() == 11
+                        && event.getMovementGranularity() ==
+                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(11, editText.getSelectionStart());
+        assertEquals(11, editText.getSelectionEnd());
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(11, editText.getSelectionStart());
+        assertEquals(11, editText.getSelectionEnd());
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getContentDescription().equals(getString(R.string.android_wiki))
+                        && event.getFromIndex() == 8
+                        && event.getToIndex() == 11
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Verify the selection position.
+        assertEquals(8, editText.getSelectionStart());
+        assertEquals(8, editText.getSelectionEnd());
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getContentDescription().equals(getString(R.string.android_wiki))
+                        && event.getFromIndex() == 4
+                        && event.getToIndex() == 7
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(4, editText.getSelectionStart());
+        assertEquals(4, editText.getSelectionEnd());
+
+        // Move to the next character and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getContentDescription().equals(getString(R.string.android_wiki))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, editText.getSelectionStart());
+        assertEquals(0, editText.getSelectionEnd());
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(0, editText.getSelectionStart());
+        assertEquals(0, editText.getSelectionEnd());
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityWordOverTextExtend() throws Exception {
+        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setVisibility(View.VISIBLE);
+                editText.setText(getString(R.string.foo_bar_baz));
+                Selection.removeSelection(editText.getText());
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                       R.string.foo_bar_baz)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+        arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 4
+                        && event.getToIndex() == 7
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(7, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 8
+                        && event.getToIndex() == 11
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(11, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Move to the previous word and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 8
+                        && event.getToIndex() == 11
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(8, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous word and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 4
+                        && event.getToIndex() == 7
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(4, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Focus the view so we can change selection.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setFocusable(true);
+                editText.requestFocus();
+            }
+        });
+
+        // Put selection at the end of the text.
+        Bundle setSelectionArgs = new Bundle();
+        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 11);
+        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 11);
+        assertTrue(text.performAction(
+                AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(editText.getText()));
+        assertEquals(11, Selection.getSelectionEnd(editText.getText()));
+
+        // Unfocus the view so we can get rid of the soft-keyboard.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.clearFocus();
+                editText.setFocusable(false);
+            }
+        });
+
+        // Move to the previous word and wait for an event.
+        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 8
+                        && event.getToIndex() == 11
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(seventhExpected);
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(editText.getText()));
+        assertEquals(8, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous word and wait for an event.
+        AccessibilityEvent eightExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 4
+                        && event.getToIndex() == 7
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(eightExpected);
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(editText.getText()));
+        assertEquals(4, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous character and wait for an event.
+        AccessibilityEvent ninethExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(ninethExpected);
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent tenthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 3
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(tenthExpected);
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(editText.getText()));
+        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent eleventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 4
+                        && event.getToIndex() == 7
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(eleventhExpected);
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(editText.getText()));
+        assertEquals(7, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next word and wait for an event.
+        AccessibilityEvent twelvthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
+                        && event.getFromIndex() == 8
+                        && event.getToIndex() == 11
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(twelvthExpected);
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(editText.getText()));
+        assertEquals(11, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(11, Selection.getSelectionStart(editText.getText()));
+        assertEquals(11, Selection.getSelectionEnd(editText.getText()));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityLineOverText() throws Exception {
+        final TextView textView = (TextView) getActivity().findViewById(R.id.text);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setVisibility(View.VISIBLE);
+                textView.setText(getString(R.string.android_wiki_short));
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                       R.string.android_wiki_short)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+
+        // Move to the next line and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 13
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(13, Selection.getSelectionStart(textView.getText()));
+        assertEquals(13, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next line and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 13
+                        && event.getToIndex() == 25
+                        && event.getMovementGranularity() ==
+                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(25, Selection.getSelectionStart(textView.getText()));
+        assertEquals(25, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next line and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 25
+                        && event.getToIndex() == 34
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(34, Selection.getSelectionStart(textView.getText()));
+        assertEquals(34, Selection.getSelectionEnd(textView.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(34, Selection.getSelectionStart(textView.getText()));
+        assertEquals(34, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the previous line and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 25
+                        && event.getToIndex() == 34
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Verify the selection position.
+        assertEquals(25, Selection.getSelectionStart(textView.getText()));
+        assertEquals(25, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the previous line and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 13
+                        && event.getToIndex() == 25
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(13, Selection.getSelectionStart(textView.getText()));
+        assertEquals(13, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the previous line and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(TextView.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 13
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(textView.getText()));
+        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(textView.getText()));
+        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityLineOverTextExtend() throws Exception {
+        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setVisibility(View.VISIBLE);
+                editText.setText(getString(R.string.android_wiki_short));
+                Selection.removeSelection(editText.getText());
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                       R.string.android_wiki_short)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+        arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
+
+        // Move to the next line and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 13
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(13, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next line and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 13
+                        && event.getToIndex() == 25
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(25, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next line and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 25
+                        && event.getToIndex() == 34
+                        && event.getMovementGranularity() ==
+                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(34, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous line and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 25
+                        && event.getToIndex() == 34
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(25, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous line and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 13
+                        && event.getToIndex() == 25
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(13, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous line and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                               AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 13
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Focus the view so we can change selection.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setFocusable(true);
+                editText.requestFocus();
+            }
+        });
+
+        // Put selection at the end of the text.
+        Bundle setSelectionArgs = new Bundle();
+        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 34);
+        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 34);
+        assertTrue(text.performAction(
+                AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
+
+        // Verify the selection position.
+        assertEquals(34, Selection.getSelectionStart(editText.getText()));
+        assertEquals(34, Selection.getSelectionEnd(editText.getText()));
+
+        // Unocus the view so we can hide the keyboard.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.clearFocus();
+                editText.setFocusable(false);
+            }
+        });
+
+        // Move to the previous line and wait for an event.
+        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 25
+                        && event.getToIndex() == 34
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(seventhExpected);
+
+        // Verify the selection position.
+        assertEquals(34, Selection.getSelectionStart(editText.getText()));
+        assertEquals(25, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous line and wait for an event.
+        AccessibilityEvent eightExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 13
+                        && event.getToIndex() == 25
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(eightExpected);
+
+        // Verify the selection position.
+        assertEquals(34, Selection.getSelectionStart(editText.getText()));
+        assertEquals(13, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous line and wait for an event.
+        AccessibilityEvent ninethExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                               AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 13
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(ninethExpected);
+
+        // Verify the selection position.
+        assertEquals(34, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(34, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next line and wait for an event.
+        AccessibilityEvent tenthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 13
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(tenthExpected);
+
+        // Verify the selection position.
+        assertEquals(34, Selection.getSelectionStart(editText.getText()));
+        assertEquals(13, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next line and wait for an event.
+        AccessibilityEvent eleventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 13
+                        && event.getToIndex() == 25
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(eleventhExpected);
+
+        // Verify the selection position.
+        assertEquals(34, Selection.getSelectionStart(editText.getText()));
+        assertEquals(25, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next line and wait for an event.
+        AccessibilityEvent twelvethExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_short))
+                        && event.getFromIndex() == 25
+                        && event.getToIndex() == 34
+                        && event.getMovementGranularity() ==
+                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(twelvethExpected);
+
+        // Verify the selection position.
+        assertEquals(34, Selection.getSelectionStart(editText.getText()));
+        assertEquals(34, Selection.getSelectionEnd(editText.getText()));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityPageOverText() throws Exception {
+        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setVisibility(View.VISIBLE);
+                editText.setText(getString(R.string.android_wiki));
+                Selection.removeSelection(editText.getText());
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                       R.string.android_wiki)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        // Move to the next page and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 53
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(53, Selection.getSelectionStart(editText.getText()));
+        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next page and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 53
+                        && event.getToIndex() == 103
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(103, Selection.getSelectionStart(editText.getText()));
+        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next page and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 103
+                        && event.getToIndex() == 153
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(153, Selection.getSelectionStart(editText.getText()));
+        assertEquals(153, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(153, Selection.getSelectionStart(editText.getText()));
+        assertEquals(153, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous page and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 103
+                        && event.getToIndex() == 153
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Verify the selection position.
+        assertEquals(103, Selection.getSelectionStart(editText.getText()));
+        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous page and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 53
+                        && event.getToIndex() == 103
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(53, Selection.getSelectionStart(editText.getText()));
+        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous page and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 53
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityPageOverTextExtend() throws Exception {
+        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setVisibility(View.VISIBLE);
+                editText.setText(getString(R.string.android_wiki));
+                Selection.removeSelection(editText.getText());
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                       R.string.android_wiki)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+        arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
+
+        // Move to the next page and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 53
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next page and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 53
+                        && event.getToIndex() == 103
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next page and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 103
+                        && event.getToIndex() == 153
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(153, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Move to the previous page and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 103
+                        && event.getToIndex() == 153
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous page and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 53
+                        && event.getToIndex() == 103
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous page and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 53
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(0, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Focus the view so we can change selection.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setFocusable(true);
+                editText.requestFocus();
+            }
+        });
+
+        // Put selection at the end of the text.
+        Bundle setSelectionArgs = new Bundle();
+        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 153);
+        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 153);
+        assertTrue(text.performAction(
+                AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
+
+        // Verify the selection position.
+        assertEquals(153, Selection.getSelectionStart(editText.getText()));
+        assertEquals(153, Selection.getSelectionEnd(editText.getText()));
+
+        // Unfocus the view so we can hide the soft-keyboard.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.clearFocus();
+                editText.setFocusable(false);
+            }
+        });
+
+        // Move to the previous page and wait for an event.
+        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 103
+                        && event.getToIndex() == 153
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(seventhExpected);
+
+        // Verify the selection position.
+        assertEquals(153, Selection.getSelectionStart(editText.getText()));
+        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous page and wait for an event.
+        AccessibilityEvent eightExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 53
+                        && event.getToIndex() == 103
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(eightExpected);
+
+        // Verify the selection position.
+        assertEquals(153, Selection.getSelectionStart(editText.getText()));
+        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous page and wait for an event.
+        AccessibilityEvent ninethExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 53
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(ninethExpected);
+
+        // Verify the selection position.
+        assertEquals(153, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(153, Selection.getSelectionStart(editText.getText()));
+        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next page and wait for an event.
+        AccessibilityEvent tenthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 0
+                        && event.getToIndex() == 53
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(tenthExpected);
+
+        // Verify the selection position.
+        assertEquals(153, Selection.getSelectionStart(editText.getText()));
+        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next page and wait for an event.
+        AccessibilityEvent eleventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 53
+                        && event.getToIndex() == 103
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(eleventhExpected);
+
+        // Verify the selection position.
+        assertEquals(153, Selection.getSelectionStart(editText.getText()));
+        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next page and wait for an event.
+        AccessibilityEvent twelvethExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki))
+                        && event.getFromIndex() == 103
+                        && event.getToIndex() == 153
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(twelvethExpected);
+
+        // Verify the selection position.
+        assertEquals(153, Selection.getSelectionStart(editText.getText()));
+        assertEquals(153, Selection.getSelectionEnd(editText.getText()));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityParagraphOverText() throws Exception {
+        final TextView textView = (TextView) getActivity().findViewById(R.id.edit);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setVisibility(View.VISIBLE);
+                textView.setText(getString(R.string.android_wiki_paragraphs));
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                       R.string.android_wiki_paragraphs)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+
+        // Move to the next paragraph and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 14
+                        && event.getMovementGranularity() ==
+                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(14, Selection.getSelectionStart(textView.getText()));
+        assertEquals(14, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next paragraph and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 16
+                        && event.getToIndex() == 32
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(32, Selection.getSelectionStart(textView.getText()));
+        assertEquals(32, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the next paragraph and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 33
+                        && event.getToIndex() == 47
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(textView.getText()));
+        assertEquals(47, Selection.getSelectionEnd(textView.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(textView.getText()));
+        assertEquals(47, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the previous paragraph and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 33
+                        && event.getToIndex() == 47
+                        && event.getMovementGranularity() ==
+                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Verify the selection position.
+        assertEquals(33, Selection.getSelectionStart(textView.getText()));
+        assertEquals(33, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the previous paragraph and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 16
+                        && event.getToIndex() == 32
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(16, Selection.getSelectionStart(textView.getText()));
+        assertEquals(16, Selection.getSelectionEnd(textView.getText()));
+
+        // Move to the previous paragraph and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 14
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(textView.getText()));
+        assertEquals(2, Selection.getSelectionEnd(textView.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(textView.getText()));
+        assertEquals(2, Selection.getSelectionEnd(textView.getText()));
+    }
+
+    @MediumTest
+    public void testActionNextAndPreviousAtGranularityParagraphOverTextExtend() throws Exception {
+        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setVisibility(View.VISIBLE);
+                editText.setText(getString(R.string.android_wiki_paragraphs));
+                Selection.removeSelection(editText.getText());
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                       R.string.android_wiki_paragraphs)).get(0);
+
+        final int granularities = text.getMovementGranularities();
+        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+
+        final Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+        arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
+
+        // Move to the next paragraph and wait for an event.
+        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 14
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(firstExpected);
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(editText.getText()));
+        assertEquals(14, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next paragraph and wait for an event.
+        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 16
+                        && event.getToIndex() == 32
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(secondExpected);
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(editText.getText()));
+        assertEquals(32, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next paragraph and wait for an event.
+        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 33
+                        && event.getToIndex() == 47
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(thirdExpected);
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(editText.getText()));
+        assertEquals(47, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(editText.getText()));
+        assertEquals(47, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous paragraph and wait for an event.
+        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 33
+                        && event.getToIndex() == 47
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fourthExpected);
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(editText.getText()));
+        assertEquals(33, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous paragraph and wait for an event.
+        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 16
+                        && event.getToIndex() == 32
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(fifthExpected);
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(editText.getText()));
+        assertEquals(16, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous paragraph and wait for an event.
+        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 14
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(sixthExpected);
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(editText.getText()));
+        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(2, Selection.getSelectionStart(editText.getText()));
+        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
+
+        // Focus the view so we can change selection.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setFocusable(true);
+                editText.requestFocus();
+            }
+        });
+
+        // Put selection at the end of the text.
+        Bundle setSelectionArgs = new Bundle();
+        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 47);
+        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 47);
+        assertTrue(text.performAction(
+                AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(editText.getText()));
+        assertEquals(47, Selection.getSelectionEnd(editText.getText()));
+
+        // Unfocus the view so we can get rid of the soft-keyboard.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.clearFocus();
+                editText.setFocusable(false);
+            }
+        });
+
+        // Move to the previous paragraph and wait for an event.
+        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 33
+                        && event.getToIndex() == 47
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(seventhExpected);
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(editText.getText()));
+        assertEquals(33, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous paragraph and wait for an event.
+        AccessibilityEvent eightExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 16
+                        && event.getToIndex() == 32
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(eightExpected);
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(editText.getText()));
+        assertEquals(16, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the previous paragraph and wait for an event.
+        AccessibilityEvent ninethExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 14
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(ninethExpected);
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(editText.getText()));
+        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no previous.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(editText.getText()));
+        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next paragraph and wait for an event.
+        AccessibilityEvent tenthExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 2
+                        && event.getToIndex() == 14
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(tenthExpected);
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(editText.getText()));
+        assertEquals(14, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next paragraph and wait for an event.
+        AccessibilityEvent eleventhExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 16
+                        && event.getToIndex() == 32
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(eleventhExpected);
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(editText.getText()));
+        assertEquals(32, Selection.getSelectionEnd(editText.getText()));
+
+        // Move to the next paragraph and wait for an event.
+        AccessibilityEvent twlevethExpected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                text.performAction(
+                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return
+                (event.getEventType() ==
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
+                        && event.getAction() ==
+                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+                        && event.getPackageName().equals(getActivity().getPackageName())
+                        && event.getClassName().equals(EditText.class.getName())
+                        && event.getText().size() > 0
+                        && event.getText().get(0).toString().equals(getString(
+                                R.string.android_wiki_paragraphs))
+                        && event.getFromIndex() == 33
+                        && event.getToIndex() == 47
+                        && event.getMovementGranularity() ==
+                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure we got the expected event.
+        assertNotNull(twlevethExpected);
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(editText.getText()));
+        assertEquals(47, Selection.getSelectionEnd(editText.getText()));
+
+        // Make sure there is no next.
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
+
+        // Verify the selection position.
+        assertEquals(47, Selection.getSelectionStart(editText.getText()));
+        assertEquals(47, Selection.getSelectionEnd(editText.getText()));
+    }
+
+    @MediumTest
+    public void testTextEditingActions() throws Exception {
+        if (!getActivity().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_INPUT_METHODS)) {
+            return;
+        }
+
+        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
+        final String textContent = getString(R.string.foo_bar_baz);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setVisibility(View.VISIBLE);
+                editText.setFocusable(true);
+                editText.requestFocus();
+                editText.setText(getString(R.string.foo_bar_baz));
+                Selection.removeSelection(editText.getText());
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                       getString(R.string.foo_bar_baz)).get(0);
+
+        // Select all text.
+        Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT,
+                editText.getText().length());
+        assertTrue(text.performAction(
+                AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
+
+        // Copy the selected text.
+        text.performAction(AccessibilityNodeInfo.ACTION_COPY);
+
+        // Set selection at the end.
+        final int textLength = editText.getText().length();
+        // Verify the selection position.
+        assertEquals(textLength, Selection.getSelectionStart(editText.getText()));
+        assertEquals(textLength, Selection.getSelectionEnd(editText.getText()));
+
+        // Paste the selected text.
+        assertTrue(text.performAction(
+                AccessibilityNodeInfo.ACTION_PASTE));
+
+        // Verify the content.
+        assertEquals(editText.getText().toString(), textContent + textContent);
+
+        // Select all text.
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT,
+                editText.getText().length());
+        assertTrue(text.performAction(
+                AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
+
+        // Cut the selected text.
+        assertTrue(text.performAction(
+                AccessibilityNodeInfo.ACTION_CUT));
+
+        // Verify the content.
+        assertTrue(TextUtils.isEmpty(editText.getText()));
+    }
+
+    public void testSetSelectionInContentDescription() throws Exception {
+        final View view = getActivity().findViewById(R.id.view);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                view.setVisibility(View.VISIBLE);
+                view.setContentDescription(getString(R.string.foo_bar_baz));
+            }
+        });
+
+        AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                       getString(R.string.foo_bar_baz)).get(0);
+
+        // Set the cursor position.
+        Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 4);
+        assertTrue(text.performAction(
+                AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
+
+        // Try and fail to set the selection longer than zero.
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 5);
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
+    }
+
+    public void testSelectionPositionForNonEditableView() throws Exception {
+        final View view = getActivity().findViewById(R.id.view);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                view.setVisibility(View.VISIBLE);
+                view.setContentDescription(getString(R.string.foo_bar_baz));
+            }
+        });
+
+        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
+               .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                       getString(R.string.foo_bar_baz)).get(0);
+
+        // Check the initial node properties.
+        assertFalse(text.isEditable());
+        assertSame(text.getTextSelectionStart(), -1);
+        assertSame(text.getTextSelectionEnd(), -1);
+
+        // Set the cursor position.
+        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                Bundle arguments = new Bundle();
+                arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
+                arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 4);
+                assertTrue(text.performAction(
+                        AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return (event.getEventType()
+                        == AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Refresh the node.
+        AccessibilityNodeInfo refreshedText = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.foo_bar_baz)).get(0);
+
+        // Check the related node properties.
+        assertFalse(refreshedText.isEditable());
+        assertSame(refreshedText.getTextSelectionStart(), 4);
+        assertSame(refreshedText.getTextSelectionEnd(), 4);
+
+        // Try to set to an invalid cursor position.
+        Bundle arguments = new Bundle();
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
+        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 5);
+        assertFalse(text.performAction(
+                AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
+
+        // Refresh the node.
+        refreshedText = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.foo_bar_baz)).get(0);
+
+        // Check the related node properties.
+        assertFalse(refreshedText.isEditable());
+        assertSame(refreshedText.getTextSelectionStart(), 4);
+        assertSame(refreshedText.getTextSelectionEnd(), 4);
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingActivity.java
new file mode 100644
index 0000000..c28e7e8
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingActivity.java
@@ -0,0 +1,35 @@
+/**
+ * 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 android.accessibilityservice.cts;
+
+import android.os.Bundle;
+
+import android.accessibilityservice.cts.R;
+
+/**
+ * Activity for testing the accessibility focus APIs exposed to
+ * accessibility services. These APIs allow moving accessibility
+ * focus in the view tree from an AccessiiblityService. Specifically,
+ * this activity is for verifying the hierarchical movement of the
+ * accessibility focus.
+ */
+public class AccessibilityViewTreeReportingActivity extends AccessibilityTestActivity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.accessibility_view_tree_reporting_test);
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
new file mode 100644
index 0000000..04a9d9d
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
@@ -0,0 +1,120 @@
+/**
+ * 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 android.accessibilityservice.cts;
+
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import android.accessibilityservice.cts.R;
+
+/**
+ * Test cases for testing the accessibility focus APIs exposed to accessibility
+ * services. This test checks how the view hierarchy is reported to accessibility
+ * services.
+ */
+public class AccessibilityViewTreeReportingTest
+        extends AccessibilityActivityTestCase<AccessibilityViewTreeReportingActivity>{
+
+    public AccessibilityViewTreeReportingTest() {
+        super(AccessibilityViewTreeReportingActivity.class);
+    }
+
+    @MediumTest
+    public void testDescendantsOfNotImportantViewReportedInOrder1() throws Exception {
+        AccessibilityNodeInfo firstFrameLayout = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.firstFrameLayout)).get(0);
+        assertNotNull(firstFrameLayout);
+        assertSame(3, firstFrameLayout.getChildCount());
+
+        // Check if the first child is the right one.
+        AccessibilityNodeInfo firstTextView = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                    R.string.firstTextView)).get(0);
+        assertEquals(firstTextView, firstFrameLayout.getChild(0));
+
+        // Check if the second child is the right one.
+        AccessibilityNodeInfo firstEditText = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
+                    R.string.firstEditText)).get(0);
+        assertEquals(firstEditText, firstFrameLayout.getChild(1));
+
+        // Check if the third child is the right one.
+        AccessibilityNodeInfo firstButton = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.firstButton)).get(0);
+        assertEquals(firstButton, firstFrameLayout.getChild(2));
+    }
+
+    @MediumTest
+    public void testDescendantsOfNotImportantViewReportedInOrder2() throws Exception {
+        AccessibilityNodeInfo secondFrameLayout = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.secondFrameLayout)).get(0);
+        assertNotNull(secondFrameLayout);
+        assertSame(3, secondFrameLayout.getChildCount());
+
+        // Check if the first child is the right one.
+        AccessibilityNodeInfo secondTextView = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.secondTextView)).get(0);
+        assertEquals(secondTextView, secondFrameLayout.getChild(0));
+
+        // Check if the second child is the right one.
+        AccessibilityNodeInfo secondEditText = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.secondEditText)).get(0);
+        assertEquals(secondEditText, secondFrameLayout.getChild(1));
+
+        // Check if the third child is the right one.
+        AccessibilityNodeInfo secondButton = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.secondButton)).get(0);
+        assertEquals(secondButton, secondFrameLayout.getChild(2));
+    }
+
+    @MediumTest
+    public void testDescendantsOfNotImportantViewReportedInOrder3() throws Exception {
+        AccessibilityNodeInfo rootLinearLayout = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.rootLinearLayout)).get(0);
+        assertNotNull(rootLinearLayout);
+        assertSame(4, rootLinearLayout.getChildCount());
+
+        // Check if the first child is the right one.
+        AccessibilityNodeInfo firstFrameLayout = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.firstFrameLayout)).get(0);
+        assertEquals(firstFrameLayout, rootLinearLayout.getChild(0));
+
+        // Check if the second child is the right one.
+        AccessibilityNodeInfo secondTextView = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.secondTextView)).get(0);
+        assertEquals(secondTextView, rootLinearLayout.getChild(1));
+
+        // Check if the third child is the right one.
+        AccessibilityNodeInfo secondEditText = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.secondEditText)).get(0);
+        assertEquals(secondEditText, rootLinearLayout.getChild(2));
+
+        // Check if the fourth child is the right one.
+        AccessibilityNodeInfo secondButton = getInstrumentation().getUiAutomation()
+            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                    getString(R.string.secondButton)).get(0);
+        assertEquals(secondButton, rootLinearLayout.getChild(3));
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivity.java
new file mode 100644
index 0000000..9070a81
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivity.java
@@ -0,0 +1,64 @@
+/**
+ * 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 android.accessibilityservice.cts;
+
+import android.os.Bundle;
+import android.view.View;
+
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.accessibilityservice.cts.R;
+
+/**
+ * Activity for testing the accessibility APIs for querying of
+ * the screen content. These APIs allow exploring the screen and
+ * requesting an action to be performed on a given view from an
+ * AccessibilityService.
+ */
+public class AccessibilityWindowQueryActivity extends AccessibilityTestActivity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.query_window_test);
+
+        findViewById(R.id.button5).setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                /* do nothing */
+            }
+        });
+        findViewById(R.id.button5).setOnLongClickListener(new View.OnLongClickListener() {
+            public boolean onLongClick(View v) {
+                return true;
+            }
+        });
+
+        findViewById(R.id.button5).setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+                info.addAction(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
+            }
+
+            @Override
+            public boolean performAccessibilityAction(View host, int action, Bundle args) {
+                if (action == R.id.foo_custom_action) {
+                    return true;
+                }
+                return super.performAccessibilityAction(host, action, args);
+            }
+        });
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
new file mode 100644
index 0000000..3a60fc0
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -0,0 +1,894 @@
+/*
+ * 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 android.accessibilityservice.cts;
+
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT;
+
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.UiAutomation;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.view.accessibility.AccessibilityWindowInfo;
+
+import android.widget.Button;
+import android.accessibilityservice.cts.R;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Test cases for testing the accessibility APIs for querying of the screen content.
+ * These APIs allow exploring the screen and requesting an action to be performed
+ * on a given view from an AccessibilityService.
+ */
+public class AccessibilityWindowQueryTest
+        extends AccessibilityActivityTestCase<AccessibilityWindowQueryActivity> {
+
+    private static final long TIMEOUT_WINDOW_STATE_IDLE = 500;
+
+    public AccessibilityWindowQueryTest() {
+        super(AccessibilityWindowQueryActivity.class);
+    }
+
+    @MediumTest
+    public void testFindByText() throws Exception {
+        // find a view by text
+        List<AccessibilityNodeInfo> buttons = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText("b");
+        assertEquals(9, buttons.size());
+    }
+
+    @MediumTest
+    public void testFindByContentDescription() throws Exception {
+        // find a view by text
+        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.contentDescription)).get(0);
+        assertNotNull(button);
+    }
+
+    @MediumTest
+    public void testTraverseWindow() throws Exception {
+        verifyNodesInAppWindow(getInstrumentation().getUiAutomation().getRootInActiveWindow());
+    }
+
+    @MediumTest
+    public void testNoWindowsAccessIfFlagNotSet() throws Exception {
+        // Make sure the windows cannot be accessed.
+        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+        assertTrue(uiAutomation.getWindows().isEmpty());
+
+        // Find a button to click on.
+        final AccessibilityNodeInfo button1 = uiAutomation.getRootInActiveWindow()
+                .findAccessibilityNodeInfosByViewId(
+                        "com.android.cts.accessibilityservice:id/button1").get(0);
+
+        // Argh...
+        final List<AccessibilityEvent> events = new ArrayList<AccessibilityEvent>();
+
+        // Click the button.
+        uiAutomation.executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                button1.performAction(AccessibilityNodeInfo.ACTION_CLICK);
+            }
+        },
+        new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
+                    events.add(event);
+                    return true;
+                }
+                return false;
+            }
+        },
+        TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure the source window cannot be accessed.
+        AccessibilityEvent event = events.get(0);
+        assertNull(event.getSource().getWindow());
+    }
+
+    @MediumTest
+    public void testTraverseAllWindows() throws Exception {
+        setAccessInteractiveWindowsFlag();
+        try {
+            UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+
+            List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
+            Rect boundsInScreen = new Rect();
+
+            final int windowCount = windows.size();
+            for (int i = 0; i < windowCount; i++) {
+                AccessibilityWindowInfo window = windows.get(i);
+
+                window.getBoundsInScreen(boundsInScreen);
+                assertFalse(boundsInScreen.isEmpty()); // Varies on screen size, emptiness check.
+                assertNull(window.getParent());
+                assertSame(0, window.getChildCount());
+                assertNull(window.getParent());
+                assertNotNull(window.getRoot());
+
+                if (window.getType() == AccessibilityWindowInfo.TYPE_APPLICATION) {
+                    assertTrue(window.isFocused());
+                    assertTrue(window.isActive());
+                    verifyNodesInAppWindow(window.getRoot());
+                } else if (window.getType() == AccessibilityWindowInfo.TYPE_SYSTEM) {
+                    assertFalse(window.isFocused());
+                    assertFalse(window.isActive());
+                }
+            }
+        } finally {
+            clearAccessInteractiveWindowsFlag();
+        }
+    }
+
+    @MediumTest
+    public void testTraverseWindowFromEvent() throws Exception {
+        setAccessInteractiveWindowsFlag();
+        try {
+            UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+
+            // Find a button to click on.
+            final AccessibilityNodeInfo button1 = uiAutomation.getRootInActiveWindow()
+                    .findAccessibilityNodeInfosByViewId(
+                            "com.android.cts.accessibilityservice:id/button1").get(0);
+
+            // Argh...
+            final List<AccessibilityEvent> events = new ArrayList<AccessibilityEvent>();
+
+            // Click the button.
+            uiAutomation.executeAndWaitForEvent(new Runnable() {
+                @Override
+                public void run() {
+                    button1.performAction(AccessibilityNodeInfo.ACTION_CLICK);
+                }
+            },
+            new UiAutomation.AccessibilityEventFilter() {
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
+                        events.add(event);
+                        return true;
+                    }
+                    return false;
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+
+            // Get the source window.
+            AccessibilityEvent event = events.get(0);
+            AccessibilityWindowInfo window = event.getSource().getWindow();
+
+            // Verify the application window.
+            Rect boundsInScreen = new Rect();
+            window.getBoundsInScreen(boundsInScreen);
+            assertFalse(boundsInScreen.isEmpty()); // Varies on screen size, so just emptiness check.
+            assertSame(window.getType(), AccessibilityWindowInfo.TYPE_APPLICATION);
+            assertTrue(window.isFocused());
+            assertTrue(window.isActive());
+            assertNull(window.getParent());
+            assertSame(0, window.getChildCount());
+            assertNotNull(window.getRoot());
+
+            // Verify the window content.
+            verifyNodesInAppWindow(window.getRoot());
+        } finally {
+            clearAccessInteractiveWindowsFlag();
+        }
+    }
+
+    @MediumTest
+    public void testInteractWithAppWindow() throws Exception {
+        setAccessInteractiveWindowsFlag();
+        try {
+            UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+
+            // Find a button to click on.
+            final AccessibilityNodeInfo button1 = uiAutomation.getRootInActiveWindow()
+                    .findAccessibilityNodeInfosByViewId(
+                            "com.android.cts.accessibilityservice:id/button1").get(0);
+
+            // Argh...
+            final List<AccessibilityEvent> events = new ArrayList<AccessibilityEvent>();
+
+            // Click the button.
+            uiAutomation.executeAndWaitForEvent(new Runnable() {
+                @Override
+                public void run() {
+                    button1.performAction(AccessibilityNodeInfo.ACTION_CLICK);
+                }
+            },
+            new UiAutomation.AccessibilityEventFilter() {
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
+                        events.add(event);
+                        return true;
+                    }
+                    return false;
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+
+            // Get the source window.
+            AccessibilityEvent event = events.get(0);
+            AccessibilityWindowInfo window = event.getSource().getWindow();
+
+            // Find a another button from the event's window.
+            final AccessibilityNodeInfo button2 = window.getRoot()
+                    .findAccessibilityNodeInfosByViewId(
+                            "com.android.cts.accessibilityservice:id/button2").get(0);
+
+            // Click the second button.
+            uiAutomation.executeAndWaitForEvent(new Runnable() {
+                @Override
+                public void run() {
+                    button2.performAction(AccessibilityNodeInfo.ACTION_CLICK);
+                }
+            },
+            new UiAutomation.AccessibilityEventFilter() {
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED;
+                }
+            },
+            TIMEOUT_ASYNC_PROCESSING);
+        } finally {
+            clearAccessInteractiveWindowsFlag();
+        }
+    }
+
+    @MediumTest
+    public void testSingleAccessibilityFocusAcrossWindows() throws Exception {
+        setAccessInteractiveWindowsFlag();
+        try {
+            // Add two more windows.
+            addTwoAppPanelWindows();
+
+            // Put accessibility focus in the first app window.
+            ensureAppWindowFocusedOrFail(0);
+            // Make sure there only one accessibility focus.
+            assertSingleAccessibilityFocus();
+
+            // Put accessibility focus in the second app window.
+            ensureAppWindowFocusedOrFail(1);
+            // Make sure there only one accessibility focus.
+            assertSingleAccessibilityFocus();
+
+            // Put accessibility focus in the third app window.
+            ensureAppWindowFocusedOrFail(2);
+            // Make sure there only one accessibility focus.
+            assertSingleAccessibilityFocus();
+        } finally {
+            ensureAccessibilityFocusCleared();
+            clearAccessInteractiveWindowsFlag();
+        }
+    }
+
+    @MediumTest
+    public void testPerformActionFocus() throws Exception {
+        // find a view and make sure it is not focused
+        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.button5)).get(0);
+        assertFalse(button.isFocused());
+
+        // focus the view
+        assertTrue(button.performAction(ACTION_FOCUS));
+
+        // find the view again and make sure it is focused
+        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
+                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
+        assertTrue(button.isFocused());
+    }
+
+    @MediumTest
+    public void testPerformActionClearFocus() throws Exception {
+        // find a view and make sure it is not focused
+        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.button5)).get(0);
+        assertFalse(button.isFocused());
+
+        // focus the view
+        assertTrue(button.performAction(ACTION_FOCUS));
+
+        // find the view again and make sure it is focused
+        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
+                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
+        assertTrue(button.isFocused());
+
+        // unfocus the view
+        assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
+
+        // find the view again and make sure it is not focused
+        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
+                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
+        assertFalse(button.isFocused());
+    }
+
+    @MediumTest
+    public void testPerformActionSelect() throws Exception {
+        // find a view and make sure it is not selected
+        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.button5)).get(0);
+        assertFalse(button.isSelected());
+
+        // select the view
+        assertTrue(button.performAction(ACTION_SELECT));
+
+        // find the view again and make sure it is selected
+        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
+                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
+        assertTrue(button.isSelected());
+    }
+
+    @MediumTest
+    public void testPerformActionClearSelection() throws Exception {
+        // find a view and make sure it is not selected
+        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.button5)).get(0);
+        assertFalse(button.isSelected());
+
+        // select the view
+        assertTrue(button.performAction(ACTION_SELECT));
+
+        // find the view again and make sure it is selected
+        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
+                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
+
+        assertTrue(button.isSelected());
+
+        // unselect the view
+        assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
+
+        // find the view again and make sure it is not selected
+        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
+                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
+        assertFalse(button.isSelected());
+    }
+
+    @MediumTest
+    public void testPerformActionClick() throws Exception {
+        // find a view and make sure it is not selected
+        final AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.button5)).get(0);
+        assertFalse(button.isSelected());
+
+        // Make an action and wait for an event.
+        AccessibilityEvent expected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                button.performAction(ACTION_CLICK);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED);
+            }
+        },
+        TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure the expected event was received.
+        assertNotNull(expected);
+    }
+
+    @MediumTest
+    public void testPerformActionLongClick() throws Exception {
+        // find a view and make sure it is not selected
+        final AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.button5)).get(0);
+        assertFalse(button.isSelected());
+
+        // Make an action and wait for an event.
+        AccessibilityEvent expected = getInstrumentation().getUiAutomation()
+                .executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                button.performAction(ACTION_LONG_CLICK);
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
+            }
+        },
+        TIMEOUT_ASYNC_PROCESSING);
+
+        // Make sure the expected event was received.
+        assertNotNull(expected);
+    }
+
+
+    @MediumTest
+    public void testPerformCustomAction() throws Exception {
+        // find a view and make sure it is not selected
+        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.button5)).get(0);
+
+        // find the custom action and perform it
+        List<AccessibilityAction> actions = button.getActionList();
+        final int actionCount = actions.size();
+        for (int i = 0; i < actionCount; i++) {
+            AccessibilityAction action = actions.get(i);
+            if (action.getId() == R.id.foo_custom_action) {
+                assertSame(action.getLabel(), "Foo");
+                // perform the action
+                assertTrue(button.performAction(action.getId()));
+                return;
+            }
+        }
+    }
+
+    @MediumTest
+    public void testGetEventSource() throws Exception {
+        // find a view and make sure it is not focused
+        final AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                        getString(R.string.button5)).get(0);
+        assertFalse(button.isSelected());
+
+        // focus and wait for the event
+        AccessibilityEvent awaitedEvent = getInstrumentation().getUiAutomation()
+            .executeAndWaitForEvent(
+                new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(button.performAction(ACTION_FOCUS));
+            }
+        },
+                new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED);
+            }
+        },
+        TIMEOUT_ASYNC_PROCESSING);
+
+        assertNotNull(awaitedEvent);
+
+        // check that last event source
+        AccessibilityNodeInfo source = awaitedEvent.getSource();
+        assertNotNull(source);
+
+        // bounds
+        Rect buttonBounds = new Rect();
+        button.getBoundsInParent(buttonBounds);
+        Rect sourceBounds = new Rect();
+        source.getBoundsInParent(sourceBounds);
+
+        assertEquals(buttonBounds.left, sourceBounds.left);
+        assertEquals(buttonBounds.right, sourceBounds.right);
+        assertEquals(buttonBounds.top, sourceBounds.top);
+        assertEquals(buttonBounds.bottom, sourceBounds.bottom);
+
+        // char sequence attributes
+        assertEquals(button.getPackageName(), source.getPackageName());
+        assertEquals(button.getClassName(), source.getClassName());
+        assertEquals(button.getText().toString(), source.getText().toString());
+        assertSame(button.getContentDescription(), source.getContentDescription());
+
+        // boolean attributes
+        assertSame(button.isFocusable(), source.isFocusable());
+        assertSame(button.isClickable(), source.isClickable());
+        assertSame(button.isEnabled(), source.isEnabled());
+        assertNotSame(button.isFocused(), source.isFocused());
+        assertSame(button.isLongClickable(), source.isLongClickable());
+        assertSame(button.isPassword(), source.isPassword());
+        assertSame(button.isSelected(), source.isSelected());
+        assertSame(button.isCheckable(), source.isCheckable());
+        assertSame(button.isChecked(), source.isChecked());
+    }
+
+    @MediumTest
+    public void testPerformGlobalActionBack() throws Exception {
+        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_BACK));
+
+        // Sleep a bit so the UI is settles.
+        waitForIdle();
+    }
+
+    @MediumTest
+    public void testPerformGlobalActionHome() throws Exception {
+        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_HOME));
+
+        // Sleep a bit so the UI is settles.
+        waitForIdle();
+    }
+
+    @MediumTest
+    public void testPerformGlobalActionRecents() throws Exception {
+        // Check whether the action succeeded.
+        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_RECENTS));
+
+        // Sleep a bit so the UI is settles.
+        waitForIdle();
+
+        // This is a necessary since the back action does not
+        // dismiss recents until they stop animating. Sigh...
+        SystemClock.sleep(5000);
+
+        // Clean up.
+        getInstrumentation().getUiAutomation().performGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_BACK);
+
+        // Sleep a bit so the UI is settles.
+        waitForIdle();
+    }
+
+    @MediumTest
+    public void testPerformGlobalActionNotifications() throws Exception {
+        // Perform the action under test
+        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS));
+
+        // Sleep a bit so the UI is settles.
+        waitForIdle();
+
+        // Clean up.
+        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_BACK));
+
+        // Sleep a bit so the UI is settles.
+        waitForIdle();
+    }
+
+    @MediumTest
+    public void testPerformGlobalActionQuickSettings() throws Exception {
+        // Check whether the action succeeded.
+        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS));
+
+        // Sleep a bit so the UI is settles.
+        waitForIdle();
+
+        // Clean up.
+        getInstrumentation().getUiAutomation().performGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_BACK);
+
+        // Sleep a bit so the UI is settles.
+        waitForIdle();
+    }
+
+    @MediumTest
+    public void testPerformGlobalActionPowerDialog() throws Exception {
+        // Check whether the action succeeded.
+        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_POWER_DIALOG));
+
+        // Sleep a bit so the UI is settles.
+        waitForIdle();
+
+        // Clean up.
+        getInstrumentation().getUiAutomation().performGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_BACK);
+
+        // Sleep a bit so the UI is settles.
+        waitForIdle();
+    }
+
+    @MediumTest
+    public void testObjectContract() throws Exception {
+        try {
+            AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
+            info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+            getInstrumentation().getUiAutomation().setServiceInfo(info);
+
+            // find a view and make sure it is not focused
+            AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
+                    .getRootInActiveWindow().findAccessibilityNodeInfosByText(
+                            getString(R.string.button5)).get(0);
+            AccessibilityNodeInfo parent = button.getParent();
+            final int childCount = parent.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                AccessibilityNodeInfo child = parent.getChild(i);
+                assertNotNull(child);
+                if (child.equals(button)) {
+                    assertEquals("Equal objects must have same hasCode.", button.hashCode(),
+                            child.hashCode());
+                    return;
+                }
+            }
+            fail("Parent's children do not have the info whose parent is the parent.");
+        } finally {
+            AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
+            info.flags &= ~AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+            getInstrumentation().getUiAutomation().setServiceInfo(info);
+        }
+    }
+
+    private void assertSingleAccessibilityFocus() {
+        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+        List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
+        AccessibilityWindowInfo focused = null;
+
+        final int windowCount = windows.size();
+        for (int i = 0; i < windowCount; i++) {
+            AccessibilityWindowInfo window = windows.get(i);
+
+            if (window.isAccessibilityFocused()) {
+                if (focused == null) {
+                    focused = window;
+
+                    AccessibilityNodeInfo root = window.getRoot();
+                    assertEquals(uiAutomation.findFocus(
+                            AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), root);
+                    assertEquals(root.findFocus(
+                            AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), root);
+                } else {
+                    throw new AssertionError("Duplicate accessibility focus");
+                }
+            } else {
+                assertNull(window.getRoot().findFocus(
+                        AccessibilityNodeInfo.FOCUS_ACCESSIBILITY));
+            }
+        }
+    }
+
+    private void ensureAppWindowFocusedOrFail(int appWindowIndex) throws TimeoutException {
+        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+        List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
+        AccessibilityWindowInfo focusTareget = null;
+
+        int visitedAppWindows = -1;
+        final int windowCount = windows.size();
+        for (int i = 0; i < windowCount; i++) {
+            AccessibilityWindowInfo window = windows.get(i);
+            if (window.getType() == AccessibilityWindowInfo.TYPE_APPLICATION) {
+                visitedAppWindows++;
+                if (appWindowIndex <= visitedAppWindows) {
+                    focusTareget = window;
+                    break;
+                }
+            }
+        }
+
+        if (focusTareget == null) {
+            throw new IllegalStateException("Couldn't find app window: " + appWindowIndex);
+        }
+
+        if (focusTareget.isAccessibilityFocused()) {
+            return;
+        }
+
+        final AccessibilityWindowInfo finalFocusTarget = focusTareget;
+        uiAutomation.executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(finalFocusTarget.getRoot().performAction(
+                        AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS));
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        windows = uiAutomation.getWindows();
+        for (int i = 0; i < windowCount; i++) {
+            AccessibilityWindowInfo window = windows.get(i);
+            if (window.getId() == focusTareget.getId()) {
+                assertTrue(window.isAccessibilityFocused());
+                break;
+            }
+        }
+    }
+
+    private void addTwoAppPanelWindows() throws TimeoutException {
+        final UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+
+        uiAutomation.waitForIdle(TIMEOUT_WINDOW_STATE_IDLE, TIMEOUT_ASYNC_PROCESSING);
+
+        // Add the first window.
+        uiAutomation.executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                getInstrumentation().runOnMainSync(new Runnable() {
+                    @Override
+                    public void run() {
+                        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+                        params.gravity = Gravity.TOP;
+                        params.width = WindowManager.LayoutParams.MATCH_PARENT;
+                        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+                        params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+                        params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+                        params.token = getActivity().getWindow().getDecorView().getWindowToken();
+
+                        Button button = new Button(getActivity());
+                        button.setText(R.string.button1);
+                        getActivity().getWindowManager().addView(button, params);
+                    }
+                });
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+
+        // Add the second window.
+        uiAutomation.executeAndWaitForEvent(new Runnable() {
+            @Override
+            public void run() {
+                getInstrumentation().runOnMainSync(new Runnable() {
+                    @Override
+                    public void run() {
+                        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+                        params.gravity = Gravity.BOTTOM;
+                        params.width = WindowManager.LayoutParams.MATCH_PARENT;
+                        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+                        params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+                        params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+                        params.token = getActivity().getWindow().getDecorView().getWindowToken();
+
+                        Button button = new Button(getActivity());
+                        button.setText(R.string.button2);
+                        getActivity().getWindowManager().addView(button, params);
+                    }
+                });
+            }
+        }, new UiAutomation.AccessibilityEventFilter() {
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
+            }
+        }, TIMEOUT_ASYNC_PROCESSING);
+    }
+
+    private void setAccessInteractiveWindowsFlag () {
+        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+        AccessibilityServiceInfo info = uiAutomation.getServiceInfo();
+        info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+        uiAutomation.setServiceInfo(info);
+    }
+
+    private void clearAccessInteractiveWindowsFlag () {
+        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+        AccessibilityServiceInfo info = uiAutomation.getServiceInfo();
+        info.flags &= ~AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+        uiAutomation.setServiceInfo(info);
+    }
+
+    private void ensureAccessibilityFocusCleared() {
+        try {
+            final UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+            uiAutomation.executeAndWaitForEvent(new Runnable() {
+                @Override
+                public void run() {
+                    List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
+                    final int windowCount = windows.size();
+                    for (int i = 0; i < windowCount; i++) {
+                        AccessibilityWindowInfo window = windows.get(i);
+                        if (window.isAccessibilityFocused()) {
+                            window.getRoot().performAction(
+                                    AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+                        }
+                    }
+                }
+            }, new UiAutomation.AccessibilityEventFilter() {
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return event.getEventType() ==
+                            AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
+                }
+            }, TIMEOUT_ASYNC_PROCESSING);
+        } catch (TimeoutException te) {
+            /* ignore */
+        }
+    }
+
+    private void verifyNodesInAppWindow(AccessibilityNodeInfo root) throws Exception {
+        try {
+            AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
+            info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+            getInstrumentation().getUiAutomation().setServiceInfo(info);
+
+            root.refresh();
+
+            // make list of expected nodes
+            List<String> classNameAndTextList = new ArrayList<String>();
+            classNameAndTextList.add("android.widget.LinearLayout");
+            classNameAndTextList.add("android.widget.LinearLayout");
+            classNameAndTextList.add("android.widget.LinearLayout");
+            classNameAndTextList.add("android.widget.LinearLayout");
+            classNameAndTextList.add("android.widget.ButtonB1");
+            classNameAndTextList.add("android.widget.ButtonB2");
+            classNameAndTextList.add("android.widget.ButtonB3");
+            classNameAndTextList.add("android.widget.ButtonB4");
+            classNameAndTextList.add("android.widget.ButtonB5");
+            classNameAndTextList.add("android.widget.ButtonB6");
+            classNameAndTextList.add("android.widget.ButtonB7");
+            classNameAndTextList.add("android.widget.ButtonB8");
+            classNameAndTextList.add("android.widget.ButtonB9");
+
+            String contentViewIdResName = "com.android.cts.accessibilityservice:id/added_content";
+            boolean verifyContent = false;
+
+            Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
+            fringe.add(root);
+
+            // do a BFS traversal and check nodes
+            while (!fringe.isEmpty()) {
+                AccessibilityNodeInfo current = fringe.poll();
+
+                if (!verifyContent
+                        && contentViewIdResName.equals(current.getViewIdResourceName())) {
+                    verifyContent = true;
+                }
+
+                if (verifyContent) {
+                    CharSequence text = current.getText();
+                    String receivedClassNameAndText = current.getClassName().toString()
+                            + ((text != null) ? text.toString() : "");
+                    String expectedClassNameAndText = classNameAndTextList.remove(0);
+
+                    assertEquals("Did not get the expected node info",
+                            expectedClassNameAndText, receivedClassNameAndText);
+                }
+
+                final int childCount = current.getChildCount();
+                for (int i = 0; i < childCount; i++) {
+                    AccessibilityNodeInfo child = current.getChild(i);
+                    fringe.add(child);
+                }
+            }
+        } finally {
+            AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
+            info.flags &= ~AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+            getInstrumentation().getUiAutomation().setServiceInfo(info);
+        }
+    }
+
+    @Override
+    protected void scrubClass(Class<?> testCaseClass) {
+        /* intentionally do not scrub */
+    }
+}
diff --git a/tests/admin/Android.mk b/tests/admin/Android.mk
new file mode 100644
index 0000000..f42de8a
--- /dev/null
+++ b/tests/admin/Android.mk
@@ -0,0 +1,40 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner mockito-target
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsAdminTestCases
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_INSTRUMENTATION_FOR := CtsAdminApp
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tests/admin/AndroidManifest.xml b/tests/admin/AndroidManifest.xml
new file mode 100644
index 0000000..d3467af
--- /dev/null
+++ b/tests/admin/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.admin.cts">
+
+  <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+  <application>
+      <uses-library android:name="android.test.runner"/>
+  </application>
+
+  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                   android:targetPackage="android.admin.app"
+                   android:label="Tests for the admin APIs.">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/admin/AndroidTest.xml b/tests/admin/AndroidTest.xml
new file mode 100644
index 0000000..6831d14
--- /dev/null
+++ b/tests/admin/AndroidTest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for the CTS device admin tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAdminApp.apk" />
+        <option name="test-file-name" value="CtsAdminTestCases.apk" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="dpm set-active-admin --user cur android.admin.app/.CtsDeviceAdminReceiver" />
+        <option name="run-command" value="dpm set-active-admin --user cur android.admin.app/.CtsDeviceAdminReceiver2" />
+        <option name="run-command" value="dpm set-device-owner --user cur android.admin.app/.CtsDeviceAdminDeviceOwner" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.admin.cts" />
+        <option name="exclude-filter" value="android.admin.app.DeactivationTest" />
+    </test>
+
+    <!-- Instrument the app to clear the device admins so the apk can be uninstalled -->
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstrumentationPreparer">
+        <option name="apk" value="CtsAdminApp.apk" />
+        <option name="package" value="android.admin.app" />
+        <option name="include-filter" value="android.admin.app.DeactivationTest" />
+        <option name="when" value="after" />
+    </target_preparer>
+</configuration>
\ No newline at end of file
diff --git a/tests/admin/OldAndroidTest.xml b/tests/admin/OldAndroidTest.xml
new file mode 100644
index 0000000..0cfada8
--- /dev/null
+++ b/tests/admin/OldAndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="CTS device admin test config">
+    <include name="common-config" />
+    <option name="run-command:run-command" value="dpm set-active-admin --user cur android.admin.app/.CtsDeviceAdminReceiver" />
+    <option name="run-command:run-command" value="dpm set-active-admin --user cur android.admin.app/.CtsDeviceAdminReceiver2" />
+</configuration>
diff --git a/tests/admin/app/Android.mk b/tests/admin/app/Android.mk
new file mode 100644
index 0000000..bf49e39
--- /dev/null
+++ b/tests/admin/app/Android.mk
@@ -0,0 +1,38 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_JAVA_LIBRARIES := guava
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsAdminApp
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/admin/app/AndroidManifest.xml b/tests/admin/app/AndroidManifest.xml
new file mode 100644
index 0000000..0834579
--- /dev/null
+++ b/tests/admin/app/AndroidManifest.xml
@@ -0,0 +1,126 @@
+<?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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.admin.app">
+    <application>
+
+        <uses-library android:name="android.test.runner"/>
+
+        <receiver android:name="android.admin.app.CtsDeviceAdminDeviceOwner"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                android:resource="@xml/device_admin" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <receiver android:name="android.admin.app.CtsDeviceAdminReceiver"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                    android:resource="@xml/device_admin" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <receiver android:name="android.admin.app.CtsDeviceAdminReceiver2"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                    android:resource="@xml/device_admin_2" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <!-- Device Admin that needs to be in the deactivated state in order
+             for tests to pass. -->
+        <receiver android:name="android.admin.app.CtsDeviceAdminDeactivatedReceiver"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                    android:resource="@xml/device_admin" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <!-- Helper Activity used by Device Admin activation tests -->
+        <activity android:name="android.admin.app.CtsDeviceAdminActivationTestActivity"
+                android:label="Device Admin activation test" />
+
+        <!-- Broken device admin: meta-data missing -->
+        <receiver android:name="android.admin.app.CtsDeviceAdminBrokenReceiver"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <!-- Broken device admin: filter doesn't match an Intent with action
+             android.app.action.DEVICE_ADMIN_ENABLED and nothing else (e.g.,
+             data) set -->
+        <receiver android:name="android.admin.app.CtsDeviceAdminBrokenReceiver2"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                    android:resource="@xml/device_admin" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+                <data android:scheme="https" />
+            </intent-filter>
+        </receiver>
+
+        <!-- Broken device admin: meta-data element doesn't point to valid
+             Device Admin configuration/description -->
+        <receiver android:name="android.admin.app.CtsDeviceAdminBrokenReceiver3"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                    android:resource="@xml/broken_device_admin" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <!-- Broken device admin: filter doesn't match Intents with action
+             android.app.action.DEVICE_ADMIN_ENABLED -->
+        <receiver android:name="android.admin.app.CtsDeviceAdminBrokenReceiver4"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                    android:resource="@xml/device_admin" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_DISABLED" />
+            </intent-filter>
+        </receiver>
+
+        <!-- Broken device admin: no intent-filter -->
+        <receiver android:name="android.admin.app.CtsDeviceAdminBrokenReceiver5"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                    android:resource="@xml/device_admin" />
+        </receiver>
+
+    </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:label="Deactivate Admins"
+        android:targetPackage="android.admin.app" >
+    </instrumentation>
+
+</manifest>
diff --git a/tests/deviceadmin/res/xml/broken_device_admin.xml b/tests/admin/app/res/xml/broken_device_admin.xml
similarity index 100%
rename from tests/deviceadmin/res/xml/broken_device_admin.xml
rename to tests/admin/app/res/xml/broken_device_admin.xml
diff --git a/tests/deviceadmin/res/xml/device_admin.xml b/tests/admin/app/res/xml/device_admin.xml
similarity index 100%
rename from tests/deviceadmin/res/xml/device_admin.xml
rename to tests/admin/app/res/xml/device_admin.xml
diff --git a/tests/deviceadmin/res/xml/device_admin_2.xml b/tests/admin/app/res/xml/device_admin_2.xml
similarity index 100%
rename from tests/deviceadmin/res/xml/device_admin_2.xml
rename to tests/admin/app/res/xml/device_admin_2.xml
diff --git a/tests/admin/app/src/android/admin/app/CtsDeviceAdminActivationTestActivity.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminActivationTestActivity.java
new file mode 100644
index 0000000..9f46949
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminActivationTestActivity.java
@@ -0,0 +1,64 @@
+/*
+ * 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 android.admin.app;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Helper {@link Activity} for CTS tests of Device Admin activation. The {@code Activity}
+ * enables tests to capture the invocations of its {@link #onActivityResult(int, int, Intent)} by
+ * providing a {@link OnActivityResultListener}.
+ */
+public class CtsDeviceAdminActivationTestActivity extends Activity {
+    public interface OnActivityResultListener {
+        void onActivityResult(int requestCode, int resultCode, Intent data);
+    }
+
+    private OnActivityResultListener mOnActivityResultListener;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Dismiss keyguard and keep screen on while this Activity is displayed.
+        // This is needed because on older platforms, when the keyguard is on, onActivityResult is
+        // not invoked when a Device Admin activation is rejected without user interaction.
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+    }
+
+    @VisibleForTesting
+    public void setOnActivityResultListener(OnActivityResultListener listener) {
+        mOnActivityResultListener = listener;
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (mOnActivityResultListener != null) {
+            mOnActivityResultListener.onActivityResult(requestCode, resultCode, data);
+            return;
+        }
+
+        super.onActivityResult(requestCode, resultCode, data);
+    }
+}
diff --git a/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver.java
new file mode 100644
index 0000000..8aec34a
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.admin.app;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class CtsDeviceAdminBrokenReceiver extends DeviceAdminReceiver {
+}
diff --git a/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver2.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver2.java
new file mode 100644
index 0000000..9895716
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver2.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.admin.app;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class CtsDeviceAdminBrokenReceiver2 extends DeviceAdminReceiver {
+}
diff --git a/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver3.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver3.java
new file mode 100644
index 0000000..0c6d2cc
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver3.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.admin.app;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class CtsDeviceAdminBrokenReceiver3 extends DeviceAdminReceiver {
+}
diff --git a/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver4.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver4.java
new file mode 100644
index 0000000..20229c6
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver4.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.admin.app;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class CtsDeviceAdminBrokenReceiver4 extends DeviceAdminReceiver {
+}
diff --git a/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver5.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver5.java
new file mode 100644
index 0000000..709dd86
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminBrokenReceiver5.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.admin.app;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class CtsDeviceAdminBrokenReceiver5 extends DeviceAdminReceiver {
+}
diff --git a/tests/admin/app/src/android/admin/app/CtsDeviceAdminDeactivatedReceiver.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminDeactivatedReceiver.java
new file mode 100644
index 0000000..fbafe0e
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminDeactivatedReceiver.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.admin.app;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class CtsDeviceAdminDeactivatedReceiver extends DeviceAdminReceiver {
+}
diff --git a/tests/admin/app/src/android/admin/app/CtsDeviceAdminDeviceOwner.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminDeviceOwner.java
new file mode 100644
index 0000000..619f700
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminDeviceOwner.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 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.admin.app;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class CtsDeviceAdminDeviceOwner extends DeviceAdminReceiver {
+
+}
diff --git a/tests/admin/app/src/android/admin/app/CtsDeviceAdminReceiver.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminReceiver.java
new file mode 100644
index 0000000..737111f
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminReceiver.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.admin.app;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class CtsDeviceAdminReceiver extends DeviceAdminReceiver {
+}
diff --git a/tests/admin/app/src/android/admin/app/CtsDeviceAdminReceiver2.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminReceiver2.java
new file mode 100644
index 0000000..9baf8b0
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminReceiver2.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.admin.app;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class CtsDeviceAdminReceiver2 extends DeviceAdminReceiver {
+}
diff --git a/tests/admin/app/src/android/admin/app/DeactivationTest.java b/tests/admin/app/src/android/admin/app/DeactivationTest.java
new file mode 100644
index 0000000..d6a7bf8
--- /dev/null
+++ b/tests/admin/app/src/android/admin/app/DeactivationTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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.admin.app;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+/**
+ * Helper to deactivate Device Admins.
+ */
+public class DeactivationTest extends AndroidTestCase {
+    private static final String PACKAGE = CtsDeviceAdminReceiver.class.getPackage().getName();
+    private static final ComponentName RECEIVER1 = new ComponentName(PACKAGE,
+            CtsDeviceAdminReceiver.class.getName());
+    private static final ComponentName RECEIVER2 = new ComponentName(PACKAGE,
+            CtsDeviceAdminReceiver2.class.getName());
+
+    // Device admin we use to reset password.  Note profile owner can do this too,
+    // but DPM.clearProfileOwner() is hidden, so we just use a device owner.
+    private static final ComponentName DEVICE_OWNER = new ComponentName(PACKAGE,
+            CtsDeviceAdminDeviceOwner.class.getName());
+
+    public void testDeactivateAdmins() throws Exception {
+        DevicePolicyManager manager = (DevicePolicyManager)
+                getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
+        assertNotNull(manager);
+
+        manager.clearDeviceOwnerApp(PACKAGE);
+
+        manager.removeActiveAdmin(RECEIVER1);
+        manager.removeActiveAdmin(RECEIVER2);
+        manager.removeActiveAdmin(DEVICE_OWNER);
+
+        for (int i = 0; i < 1000 && isActive(manager); i++) {
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+        assertFalse(isActive(manager));
+    }
+
+    private boolean isActive(DevicePolicyManager manager) {
+        return manager.isAdminActive(RECEIVER1) ||
+                manager.isAdminActive(RECEIVER2) ||
+                manager.isAdminActive(DEVICE_OWNER);
+    }
+}
\ No newline at end of file
diff --git a/tests/admin/src/android/admin/cts/DeviceAdminActivationTest.java b/tests/admin/src/android/admin/cts/DeviceAdminActivationTest.java
new file mode 100644
index 0000000..e3b7c4b
--- /dev/null
+++ b/tests/admin/src/android/admin/cts/DeviceAdminActivationTest.java
@@ -0,0 +1,204 @@
+/*
+ * 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 android.admin.cts;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.admin.app.CtsDeviceAdminBrokenReceiver;
+import android.admin.app.CtsDeviceAdminBrokenReceiver2;
+import android.admin.app.CtsDeviceAdminBrokenReceiver3;
+import android.admin.app.CtsDeviceAdminBrokenReceiver4;
+import android.admin.app.CtsDeviceAdminBrokenReceiver5;
+import android.admin.app.CtsDeviceAdminDeactivatedReceiver;
+import android.admin.app.CtsDeviceAdminActivationTestActivity;
+import android.admin.app.CtsDeviceAdminActivationTestActivity.OnActivityResultListener;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for the standard way of activating a Device Admin: by starting system UI via an
+ * {@link Intent} with {@link DevicePolicyManager#ACTION_ADD_DEVICE_ADMIN}. The test requires that
+ * the {@code CtsDeviceAdmin.apk} be installed.
+ */
+public class DeviceAdminActivationTest
+    extends ActivityInstrumentationTestCase2<CtsDeviceAdminActivationTestActivity> {
+
+    private static final String TAG = DeviceAdminActivationTest.class.getSimpleName();
+
+    // IMPLEMENTATION NOTE: Because Device Admin activation requires the use of
+    // Activity.startActivityForResult, this test creates an empty Activity which then invokes
+    // startActivityForResult.
+
+    private static final int REQUEST_CODE_ACTIVATE_ADMIN = 1;
+
+    /**
+     * Maximum duration of time (milliseconds) after which the effects of programmatic actions in
+     * this test should have affected the UI.
+     */
+    private static final int UI_EFFECT_TIMEOUT_MILLIS = 5000;
+
+    private boolean mDeviceAdmin;
+    @Mock private OnActivityResultListener mMockOnActivityResultListener;
+
+    public DeviceAdminActivationTest() {
+        super(CtsDeviceAdminActivationTestActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+        getActivity().setOnActivityResultListener(mMockOnActivityResultListener);
+        mDeviceAdmin = getInstrumentation().getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_DEVICE_ADMIN);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            finishActivateDeviceAdminActivity();
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    public void testActivateGoodReceiverDisplaysActivationUi() throws Exception {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testActivateGoodReceiverDisplaysActivationUi");
+            return;
+        }
+        assertDeviceAdminDeactivated(CtsDeviceAdminDeactivatedReceiver.class);
+        startAddDeviceAdminActivityForResult(CtsDeviceAdminDeactivatedReceiver.class);
+        assertWithTimeoutOnActivityResultNotInvoked();
+        // The UI is up and running. Assert that dismissing the UI returns the corresponding result
+        // to the test activity.
+        finishActivateDeviceAdminActivity();
+        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
+        assertDeviceAdminDeactivated(CtsDeviceAdminDeactivatedReceiver.class);
+    }
+
+    public void testActivateBrokenReceiverFails() throws Exception {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testActivateBrokenReceiverFails");
+            return;
+        }
+        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver.class);
+        startAddDeviceAdminActivityForResult(CtsDeviceAdminBrokenReceiver.class);
+        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
+        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver.class);
+    }
+
+    public void testActivateBrokenReceiver2Fails() throws Exception {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testActivateBrokenReceiver2Fails");
+            return;
+        }
+        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver2.class);
+        startAddDeviceAdminActivityForResult(CtsDeviceAdminBrokenReceiver2.class);
+        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
+        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver2.class);
+    }
+
+    public void testActivateBrokenReceiver3Fails() throws Exception {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testActivateBrokenReceiver3Fails");
+            return;
+        }
+        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver3.class);
+        startAddDeviceAdminActivityForResult(CtsDeviceAdminBrokenReceiver3.class);
+        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
+        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver3.class);
+    }
+
+    public void testActivateBrokenReceiver4Fails() throws Exception {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testActivateBrokenReceiver4Fails");
+            return;
+        }
+        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver4.class);
+        startAddDeviceAdminActivityForResult(CtsDeviceAdminBrokenReceiver4.class);
+        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
+        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver4.class);
+    }
+
+    public void testActivateBrokenReceiver5Fails() throws Exception {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testActivateBrokenReceiver5Fails");
+            return;
+        }
+        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver5.class);
+        startAddDeviceAdminActivityForResult(CtsDeviceAdminBrokenReceiver5.class);
+        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
+        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver5.class);
+    }
+
+    private void startAddDeviceAdminActivityForResult(Class<?> receiverClass) {
+        getActivity().startActivityForResult(
+                getAddDeviceAdminIntent(receiverClass),
+                REQUEST_CODE_ACTIVATE_ADMIN);
+    }
+
+    private Intent getAddDeviceAdminIntent(Class<?> receiverClass) {
+        return new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
+            .putExtra(
+                    DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+                    new ComponentName(
+                            getInstrumentation().getTargetContext(),
+                            receiverClass));
+    }
+
+    private void assertWithTimeoutOnActivityResultNotInvoked() {
+        SystemClock.sleep(UI_EFFECT_TIMEOUT_MILLIS);
+        Mockito.verify(mMockOnActivityResultListener, Mockito.never())
+                .onActivityResult(
+                        Mockito.eq(REQUEST_CODE_ACTIVATE_ADMIN),
+                        Mockito.anyInt(),
+                        Mockito.any(Intent.class));
+    }
+
+    private void assertWithTimeoutOnActivityResultInvokedWithResultCode(int expectedResultCode) {
+        ArgumentCaptor<Integer> resultCodeCaptor = ArgumentCaptor.forClass(int.class);
+        Mockito.verify(mMockOnActivityResultListener, Mockito.timeout(UI_EFFECT_TIMEOUT_MILLIS))
+                .onActivityResult(
+                        Mockito.eq(REQUEST_CODE_ACTIVATE_ADMIN),
+                        resultCodeCaptor.capture(),
+                        Mockito.any(Intent.class));
+        assertEquals(expectedResultCode, (int) resultCodeCaptor.getValue());
+    }
+
+    private void finishActivateDeviceAdminActivity() {
+        getActivity().finishActivity(REQUEST_CODE_ACTIVATE_ADMIN);
+    }
+
+    private void assertDeviceAdminDeactivated(Class<?> receiverClass) {
+        DevicePolicyManager devicePolicyManager =
+                (DevicePolicyManager) getActivity().getSystemService(
+                        Context.DEVICE_POLICY_SERVICE);
+        assertFalse(devicePolicyManager.isAdminActive(
+                new ComponentName(getInstrumentation().getTargetContext(), receiverClass)));
+    }
+}
diff --git a/tests/admin/src/android/admin/cts/DeviceAdminInfoTest.java b/tests/admin/src/android/admin/cts/DeviceAdminInfoTest.java
new file mode 100644
index 0000000..ca1b340
--- /dev/null
+++ b/tests/admin/src/android/admin/cts/DeviceAdminInfoTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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 android.admin.cts;
+
+import android.app.admin.DeviceAdminInfo;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+public class DeviceAdminInfoTest extends AndroidTestCase {
+
+    private static final String TAG = DeviceAdminInfoTest.class.getSimpleName();
+
+    private PackageManager mPackageManager;
+    private ComponentName mComponent;
+    private ComponentName mSecondComponent;
+    private boolean mDeviceAdmin;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mPackageManager = mContext.getPackageManager();
+        mComponent = getReceiverComponent();
+        mSecondComponent = getSecondReceiverComponent();
+        mDeviceAdmin =
+                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
+    }
+
+    static ComponentName getReceiverComponent() {
+        return new ComponentName("android.admin.app", "android.admin.app.CtsDeviceAdminReceiver");
+    }
+
+    static ComponentName getSecondReceiverComponent() {
+        return new ComponentName("android.admin.app", "android.admin.app.CtsDeviceAdminReceiver2");
+    }
+
+    public void testDeviceAdminInfo() throws Exception {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testDeviceAdminInfo");
+            return;
+        }
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = mPackageManager.getReceiverInfo(mComponent,
+                PackageManager.GET_META_DATA);
+
+        DeviceAdminInfo info = new DeviceAdminInfo(mContext, resolveInfo);
+        assertEquals(mComponent, info.getComponent());
+        assertEquals(mComponent.getPackageName(), info.getPackageName());
+        assertEquals(mComponent.getClassName(), info.getReceiverName());
+
+        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_FORCE_LOCK));
+        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD));
+        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_RESET_PASSWORD));
+        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_WATCH_LOGIN));
+        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_WIPE_DATA));
+
+        assertEquals("force-lock",
+                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_FORCE_LOCK));
+        assertEquals("limit-password",
+                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD));
+        assertEquals("reset-password",
+                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_RESET_PASSWORD));
+        assertEquals("watch-login",
+                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_WATCH_LOGIN));
+        assertEquals("wipe-data",
+                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_WIPE_DATA));
+    }
+
+    public void testDeviceAdminInfo2() throws Exception {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testDeviceAdminInfo2");
+            return;
+        }
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = mPackageManager.getReceiverInfo(mSecondComponent,
+                PackageManager.GET_META_DATA);
+
+        DeviceAdminInfo info = new DeviceAdminInfo(mContext, resolveInfo);
+        assertEquals(mSecondComponent, info.getComponent());
+        assertEquals(mSecondComponent.getPackageName(), info.getPackageName());
+        assertEquals(mSecondComponent.getClassName(), info.getReceiverName());
+
+        assertFalse(info.usesPolicy(DeviceAdminInfo.USES_POLICY_FORCE_LOCK));
+        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD));
+        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_RESET_PASSWORD));
+        assertFalse(info.usesPolicy(DeviceAdminInfo.USES_POLICY_WATCH_LOGIN));
+        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_WIPE_DATA));
+
+        assertEquals("force-lock",
+                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_FORCE_LOCK));
+        assertEquals("limit-password",
+                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD));
+        assertEquals("reset-password",
+                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_RESET_PASSWORD));
+        assertEquals("watch-login",
+                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_WATCH_LOGIN));
+        assertEquals("wipe-data",
+                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_WIPE_DATA));
+    }
+}
diff --git a/tests/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java b/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java
similarity index 100%
rename from tests/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java
rename to tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
new file mode 100644
index 0000000..2e79557
--- /dev/null
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -0,0 +1,1160 @@
+/*
+ * 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 android.admin.cts;
+
+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.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.os.Build;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+import java.util.List;
+
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+
+/**
+ * TODO: Make sure DO APIs are not called by PO.
+ * Test that exercises {@link DevicePolicyManager}. The test requires that the
+ * CtsDeviceAdminReceiver be installed via the CtsDeviceAdmin.apk and be
+ * activated via "Settings > Location & security > Select device administrators".
+ */
+public class DevicePolicyManagerTest extends AndroidTestCase {
+
+    private static final String TAG = DevicePolicyManagerTest.class.getSimpleName();
+
+    private DevicePolicyManager mDevicePolicyManager;
+    private ComponentName mComponent;
+    private ComponentName mSecondComponent;
+    private boolean mDeviceAdmin;
+    private boolean mManagedProfiles;
+    private PackageManager mPackageManager;
+
+    private static final String TEST_CA_STRING1 =
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIICVzCCAgGgAwIBAgIJAMvnLHnnfO/IMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD\n" +
+            "VQQGEwJJTjELMAkGA1UECAwCQVAxDDAKBgNVBAcMA0hZRDEVMBMGA1UECgwMSU1G\n" +
+            "TCBQVlQgTFREMRAwDgYDVQQLDAdJTUZMIE9VMRIwEAYDVQQDDAlJTUZMLklORk8x\n" +
+            "HzAdBgkqhkiG9w0BCQEWEHJhbWVzaEBpbWZsLmluZm8wHhcNMTMwODI4MDk0NDA5\n" +
+            "WhcNMjMwODI2MDk0NDA5WjCBhjELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAkFQMQww\n" +
+            "CgYDVQQHDANIWUQxFTATBgNVBAoMDElNRkwgUFZUIExURDEQMA4GA1UECwwHSU1G\n" +
+            "TCBPVTESMBAGA1UEAwwJSU1GTC5JTkZPMR8wHQYJKoZIhvcNAQkBFhByYW1lc2hA\n" +
+            "aW1mbC5pbmZvMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ738cbTQlNIO7O6nV/f\n" +
+            "DJTMvWbPkyHYX8CQ7yXiAzEiZ5bzKJjDJmpRAkUrVinljKns2l6C4++l/5A7pFOO\n" +
+            "33kCAwEAAaNQME4wHQYDVR0OBBYEFOdbZP7LaMbgeZYPuds2CeSonmYxMB8GA1Ud\n" +
+            "IwQYMBaAFOdbZP7LaMbgeZYPuds2CeSonmYxMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" +
+            "hvcNAQEFBQADQQBdrk6J9koyylMtl/zRfiMAc2zgeC825fgP6421NTxs1rjLs1HG\n" +
+            "VcUyQ1/e7WQgOaBHi9TefUJi+4PSVSluOXon\n" +
+            "-----END CERTIFICATE-----";
+
+    private static final String MANAGED_PROVISIONING_PKG = "com.android.managedprovisioning";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDevicePolicyManager = (DevicePolicyManager)
+                mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        mComponent = DeviceAdminInfoTest.getReceiverComponent();
+        mPackageManager = mContext.getPackageManager();
+        mSecondComponent = DeviceAdminInfoTest.getSecondReceiverComponent();
+        mDeviceAdmin = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
+        mManagedProfiles = mDeviceAdmin
+                && mPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS);
+        setBlankPassword();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        setBlankPassword();
+    }
+
+    private void setBlankPassword() {
+        if (!mDeviceAdmin) {
+            return;
+        }
+        // Reset the password to nothing for future tests...
+        mDevicePolicyManager.setPasswordQuality(mComponent,
+                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 0);
+
+        // Note resetPassword() doesn't take "who", but because the caller package has
+        assertTrue(mDevicePolicyManager.resetPassword("", 0));
+    }
+
+    public void testGetActiveAdmins() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testGetActiveAdmins");
+            return;
+        }
+        List<ComponentName> activeAdmins = mDevicePolicyManager.getActiveAdmins();
+        assertFalse(activeAdmins.isEmpty());
+        assertTrue(activeAdmins.contains(mComponent));
+        assertTrue(mDevicePolicyManager.isAdminActive(mComponent));
+    }
+
+    public void testGetMaximumFailedPasswordsForWipe() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testGetMaximumFailedPasswordsForWipe");
+            return;
+        }
+        mDevicePolicyManager.setMaximumFailedPasswordsForWipe(mComponent, 3);
+        assertEquals(3, mDevicePolicyManager.getMaximumFailedPasswordsForWipe(mComponent));
+
+        mDevicePolicyManager.setMaximumFailedPasswordsForWipe(mComponent, 5);
+        assertEquals(5, mDevicePolicyManager.getMaximumFailedPasswordsForWipe(mComponent));
+    }
+
+    public void testPasswordQuality_something() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordQuality_something");
+            return;
+        }
+        mDevicePolicyManager.setPasswordQuality(mComponent,
+                DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
+                mDevicePolicyManager.getPasswordQuality(mComponent));
+        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
+
+        String caseDescription = "initial";
+        assertPasswordSucceeds("1234", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordSucceeds("abcd1234", caseDescription);
+
+        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 10);
+        caseDescription = "minimum password length = 10";
+        assertEquals(10, mDevicePolicyManager.getPasswordMinimumLength(mComponent));
+        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
+
+        assertPasswordFails("1234", caseDescription);
+        assertPasswordFails("abcd", caseDescription);
+        assertPasswordFails("abcd1234", caseDescription);
+
+        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 4);
+        caseDescription = "minimum password length = 4";
+        assertEquals(4, mDevicePolicyManager.getPasswordMinimumLength(
+                mComponent));
+        assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
+
+        assertPasswordSucceeds("1234", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordSucceeds("abcd1234", caseDescription);
+    }
+
+    public void testPasswordQuality_numeric() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordQuality_numeric");
+            return;
+        }
+        mDevicePolicyManager.setPasswordQuality(mComponent,
+                DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
+        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
+                mDevicePolicyManager.getPasswordQuality(mComponent));
+        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
+
+        String caseDescription = "initial";
+        assertPasswordSucceeds("1234", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordSucceeds("abcd1234", caseDescription);
+
+        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 10);
+        caseDescription = "minimum password length = 10";
+        assertEquals(10, mDevicePolicyManager.getPasswordMinimumLength(mComponent));
+        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
+
+        assertPasswordFails("1234", caseDescription);
+        assertPasswordFails("abcd", caseDescription);
+        assertPasswordFails("abcd1234", caseDescription);
+
+        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 4);
+        caseDescription = "minimum password length = 4";
+        assertEquals(4, mDevicePolicyManager.getPasswordMinimumLength(
+                mComponent));
+        assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
+
+        assertPasswordSucceeds("1234", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordSucceeds("abcd1234", caseDescription);
+    }
+
+    public void testPasswordQuality_alphabetic() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordQuality_alphabetic");
+            return;
+        }
+        mDevicePolicyManager.setPasswordQuality(mComponent,
+                DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
+        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
+                mDevicePolicyManager.getPasswordQuality(mComponent));
+        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
+
+        String caseDescription = "initial";
+        assertPasswordFails("1234", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordSucceeds("abcd1234", caseDescription);
+
+        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 10);
+        caseDescription = "minimum password length = 10";
+        assertEquals(10, mDevicePolicyManager.getPasswordMinimumLength(mComponent));
+        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
+
+        assertPasswordFails("1234", caseDescription);
+        assertPasswordFails("abcd", caseDescription);
+        assertPasswordFails("abcd1234", caseDescription);
+
+        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 4);
+        caseDescription = "minimum password length = 4";
+        assertEquals(4, mDevicePolicyManager.getPasswordMinimumLength(
+                mComponent));
+        assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
+
+        assertPasswordFails("1234", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordSucceeds("abcd1234", caseDescription);
+    }
+
+    public void testPasswordQuality_alphanumeric() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordQuality_alphanumeric");
+            return;
+        }
+        mDevicePolicyManager.setPasswordQuality(mComponent,
+                DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
+        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
+                mDevicePolicyManager.getPasswordQuality(mComponent));
+        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
+
+        String caseDescription = "initial";
+        assertPasswordFails("1234", caseDescription);
+        assertPasswordFails("abcd", caseDescription);
+        assertPasswordSucceeds("abcd1234", caseDescription);
+
+        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 10);
+        caseDescription = "minimum password length = 10";
+        assertEquals(10, mDevicePolicyManager.getPasswordMinimumLength(mComponent));
+        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
+
+        assertPasswordFails("1234", caseDescription);
+        assertPasswordFails("abcd", caseDescription);
+        assertPasswordFails("abcd1234", caseDescription);
+
+        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 4);
+        caseDescription = "minimum password length = 4";
+        assertEquals(4, mDevicePolicyManager.getPasswordMinimumLength(
+                mComponent));
+        assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
+
+        assertPasswordFails("1234", caseDescription);
+        assertPasswordFails("abcd", caseDescription);
+        assertPasswordSucceeds("abcd1234", caseDescription);
+    }
+
+    public void testPasswordQuality_complexUpperCase() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordQuality_complexUpperCase");
+            return;
+        }
+
+        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
+        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
+        resetComplexPasswordRestrictions();
+
+        String caseDescription = "minimum UpperCase=0";
+        assertPasswordSucceeds("abc1", caseDescription);
+        assertPasswordSucceeds("aBc1", caseDescription);
+        assertPasswordSucceeds("ABC1", caseDescription);
+        assertPasswordSucceeds("ABCD", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumUpperCase(mComponent, 1);
+        assertEquals(1, mDevicePolicyManager.getPasswordMinimumUpperCase(mComponent));
+        caseDescription = "minimum UpperCase=1";
+        assertPasswordFails("abc1", caseDescription);
+        assertPasswordSucceeds("aBc1", caseDescription);
+        assertPasswordSucceeds("ABC1", caseDescription);
+        assertPasswordSucceeds("ABCD", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumUpperCase(mComponent, 3);
+        assertEquals(3, mDevicePolicyManager.getPasswordMinimumUpperCase(mComponent));
+        caseDescription = "minimum UpperCase=3";
+        assertPasswordFails("abc1", caseDescription);
+        assertPasswordFails("aBC1", caseDescription);
+        assertPasswordSucceeds("ABC1", caseDescription);
+        assertPasswordSucceeds("ABCD", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+    }
+
+    public void testPasswordQuality_complexLowerCase() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordQuality_complexLowerCase");
+            return;
+        }
+
+        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
+        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
+        resetComplexPasswordRestrictions();
+
+        String caseDescription = "minimum LowerCase=0";
+        assertPasswordSucceeds("ABCD", caseDescription);
+        assertPasswordSucceeds("aBC1", caseDescription);
+        assertPasswordSucceeds("abc1", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumLowerCase(mComponent, 1);
+        assertEquals(1, mDevicePolicyManager.getPasswordMinimumLowerCase(mComponent));
+        caseDescription = "minimum LowerCase=1";
+        assertPasswordFails("ABCD", caseDescription);
+        assertPasswordSucceeds("aBC1", caseDescription);
+        assertPasswordSucceeds("abc1", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumLowerCase(mComponent, 3);
+        assertEquals(3, mDevicePolicyManager.getPasswordMinimumLowerCase(mComponent));
+        caseDescription = "minimum LowerCase=3";
+        assertPasswordFails("ABCD", caseDescription);
+        assertPasswordFails("aBC1", caseDescription);
+        assertPasswordSucceeds("abc1", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+    }
+
+    public void testPasswordQuality_complexLetters() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordQuality_complexLetters");
+            return;
+        }
+
+        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
+        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
+        resetComplexPasswordRestrictions();
+
+        String caseDescription = "minimum Letters=0";
+        assertPasswordSucceeds("1234", caseDescription);
+        assertPasswordSucceeds("a123", caseDescription);
+        assertPasswordSucceeds("abc1", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumLetters(mComponent, 1);
+        assertEquals(1, mDevicePolicyManager.getPasswordMinimumLetters(mComponent));
+        caseDescription = "minimum Letters=1";
+        assertPasswordFails("1234", caseDescription);
+        assertPasswordSucceeds("a123", caseDescription);
+        assertPasswordSucceeds("abc1", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumLetters(mComponent, 3);
+        assertEquals(3, mDevicePolicyManager.getPasswordMinimumLetters(mComponent));
+        caseDescription = "minimum Letters=3";
+        assertPasswordFails("1234", caseDescription);
+        assertPasswordFails("a123", caseDescription);
+        assertPasswordSucceeds("abc1", caseDescription);
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+    }
+
+    public void testPasswordQuality_complexNumeric() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordQuality_complexNumeric");
+            return;
+        }
+
+        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
+        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
+        resetComplexPasswordRestrictions();
+
+        String caseDescription = "minimum Numeric=0";
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordSucceeds("1abc", caseDescription);
+        assertPasswordSucceeds("123a", caseDescription);
+        assertPasswordSucceeds("1234", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumNumeric(mComponent, 1);
+        assertEquals(1, mDevicePolicyManager.getPasswordMinimumNumeric(mComponent));
+        caseDescription = "minimum Numeric=1";
+        assertPasswordFails("abcd", caseDescription);
+        assertPasswordSucceeds("1abc", caseDescription);
+        assertPasswordSucceeds("123a", caseDescription);
+        assertPasswordSucceeds("1234", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumNumeric(mComponent, 3);
+        assertEquals(3, mDevicePolicyManager.getPasswordMinimumNumeric(mComponent));
+        caseDescription = "minimum Numeric=3";
+        assertPasswordFails("abcd", caseDescription);
+        assertPasswordFails("1abc", caseDescription);
+        assertPasswordSucceeds("123a", caseDescription);
+        assertPasswordSucceeds("1234", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+    }
+
+    public void testPasswordQuality_complexSymbols() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordQuality_complexSymbols");
+            return;
+        }
+
+        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
+        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
+        resetComplexPasswordRestrictions();
+
+        String caseDescription = "minimum Symbols=0";
+        assertPasswordSucceeds("abcd", caseDescription);
+        assertPasswordSucceeds("_bc1", caseDescription);
+        assertPasswordSucceeds("@#!1", caseDescription);
+        assertPasswordSucceeds("_@#!", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumSymbols(mComponent, 1);
+        assertEquals(1, mDevicePolicyManager.getPasswordMinimumSymbols(mComponent));
+        caseDescription = "minimum Symbols=1";
+        assertPasswordFails("abcd", caseDescription);
+        assertPasswordSucceeds("_bc1", caseDescription);
+        assertPasswordSucceeds("@#!1", caseDescription);
+        assertPasswordSucceeds("_@#!", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumSymbols(mComponent, 3);
+        assertEquals(3, mDevicePolicyManager.getPasswordMinimumSymbols(mComponent));
+        caseDescription = "minimum Symbols=3";
+        assertPasswordFails("abcd", caseDescription);
+        assertPasswordFails("_bc1", caseDescription);
+        assertPasswordSucceeds("@#!1", caseDescription);
+        assertPasswordSucceeds("_@#!", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+    }
+
+    public void testPasswordQuality_complexNonLetter() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordQuality_complexNonLetter");
+            return;
+        }
+
+        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
+        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
+        resetComplexPasswordRestrictions();
+
+        String caseDescription = "minimum NonLetter=0";
+        assertPasswordSucceeds("Abcd", caseDescription);
+        assertPasswordSucceeds("_bcd", caseDescription);
+        assertPasswordSucceeds("3bcd", caseDescription);
+        assertPasswordSucceeds("_@3c", caseDescription);
+        assertPasswordSucceeds("_25!", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumNonLetter(mComponent, 1);
+        assertEquals(1, mDevicePolicyManager.getPasswordMinimumNonLetter(mComponent));
+        caseDescription = "minimum NonLetter=1";
+        assertPasswordFails("Abcd", caseDescription);
+        assertPasswordSucceeds("_bcd", caseDescription);
+        assertPasswordSucceeds("3bcd", caseDescription);
+        assertPasswordSucceeds("_@3c", caseDescription);
+        assertPasswordSucceeds("_25!", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+
+        mDevicePolicyManager.setPasswordMinimumNonLetter(mComponent, 3);
+        assertEquals(3, mDevicePolicyManager.getPasswordMinimumNonLetter(mComponent));
+        caseDescription = "minimum NonLetter=3";
+        assertPasswordFails("Abcd", caseDescription);
+        assertPasswordFails("_bcd", caseDescription);
+        assertPasswordFails("3bcd", caseDescription);
+        assertPasswordSucceeds("_@3c", caseDescription);
+        assertPasswordSucceeds("_25!", caseDescription);
+        assertPasswordFails("123", caseDescription); // too short
+    }
+
+    public void testPasswordHistoryLength() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordHistoryLength");
+            return;
+        }
+        // Password history length restriction is only imposed if password quality is at least
+        // numeric.
+        mDevicePolicyManager.setPasswordQuality(mComponent,
+                DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
+        int originalValue = mDevicePolicyManager.getPasswordHistoryLength(mComponent);
+        try {
+            mDevicePolicyManager.setPasswordHistoryLength(mComponent, 3);
+            assertEquals(3, mDevicePolicyManager.getPasswordHistoryLength(mComponent));
+            // Although it would make sense we cannot test if password history restrictions
+            // are enforced as DevicePolicyManagerService.resetPassword fails to do so at the
+            // moment. See b/17707820
+        } finally {
+            mDevicePolicyManager.setPasswordHistoryLength(mComponent, originalValue);
+        }
+    }
+
+    public void testPasswordExpirationTimeout() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testPasswordExpirationTimeout");
+            return;
+        }
+        long originalValue = mDevicePolicyManager.getPasswordExpirationTimeout(mComponent);
+        try {
+            for (long testLength : new long[] {
+                    0L, 864000000L /* ten days */, 8640000000L /* 100 days */}) {
+                mDevicePolicyManager.setPasswordExpirationTimeout(mComponent, testLength);
+                assertEquals(testLength,
+                        mDevicePolicyManager.getPasswordExpirationTimeout(mComponent));
+            }
+        } finally {
+            mDevicePolicyManager.setPasswordExpirationTimeout(mComponent, originalValue);
+        }
+    }
+
+    public void testKeyguardDisabledFeatures() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testKeyguardDisabledFeatures");
+            return;
+        }
+        int originalValue = mDevicePolicyManager.getKeyguardDisabledFeatures(mComponent);
+        try {
+            for (int which = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+                    which < 2 * DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; ++which) {
+                mDevicePolicyManager.setKeyguardDisabledFeatures(mComponent, which);
+                assertEquals(which, mDevicePolicyManager.getKeyguardDisabledFeatures(mComponent));
+            }
+        } finally {
+            mDevicePolicyManager.setKeyguardDisabledFeatures(mComponent, originalValue);
+        }
+    }
+
+    public void testCreateUser_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testCreateUser_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.createUser(mComponent, "user name");
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testRemoveUser_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testRemoveUser_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.removeUser(mComponent, null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetApplicationHidden_failIfNotDeviceOrProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetApplicationHidden_failIfNotDeviceOrProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setApplicationHidden(mComponent, "com.google.anything", true);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testIsApplicationHidden_failIfNotDeviceOrProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testIsApplicationHidden_failIfNotDeviceOrProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.isApplicationHidden(mComponent, "com.google.anything");
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetGlobalSetting_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetGlobalSetting_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setGlobalSetting(mComponent,
+                    Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, "1");
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetSecureSetting_failIfNotDeviceOrProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetSecureSetting_failIfNotDeviceOrProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setSecureSetting(mComponent,
+                    Settings.Secure.INSTALL_NON_MARKET_APPS, "1");
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetMasterVolumeMuted_failIfNotDeviceOrProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetMasterVolumeMuted_failIfNotDeviceOrProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setMasterVolumeMuted(mComponent, true);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testIsMasterVolumeMuted_failIfNotDeviceOrProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetMasterVolumeMuted_failIfNotDeviceOrProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.isMasterVolumeMuted(mComponent);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetRecommendedGlobalProxy_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetRecommendedGlobalProxy_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setRecommendedGlobalProxy(mComponent, null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetLockTaskPackages_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetLockTaskPackages_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setLockTaskPackages(mComponent, new String[] {"package"});
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+        }
+    }
+
+    // This test registers itself as DO, so this is no longer testable.  We do a positive test
+    // for clearDeviceOwnerApp()
+    @Suppress
+    public void testClearDeviceOwnerApp_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testClearDeviceOwnerApp_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.clearDeviceOwnerApp("android.admin.app");
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSwitchUser_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSwitchUser_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.switchUser(mComponent, null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testCreateAndInitializeUser_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testCreateAndInitializeUser_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.createAndInitializeUser(mComponent, "name", "admin name",
+                        mComponent, null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testInstallCaCert_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testInstallCaCert_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.installCaCert(mComponent,
+                    TEST_CA_STRING1.getBytes());
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testInstallCaCert_failIfNotCertInstaller() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testInstallCaCert_failIfNotCertInstaller");
+            return;
+        }
+        try {
+            // Delegated cert installer is identified by using null as the first argument.
+            mDevicePolicyManager.installCaCert(null, TEST_CA_STRING1.getBytes());
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testUninstallCaCert_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testUninstallCaCert_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.uninstallCaCert(mComponent,
+                    TEST_CA_STRING1.getBytes());
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testUninstallCaCert_failIfNotCertInstaller() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testUninstallCaCert_failIfNotCertInstaller");
+            return;
+        }
+        try {
+            // Delegated cert installer is identified by using null as the first argument.
+            mDevicePolicyManager.uninstallCaCert(null, TEST_CA_STRING1.getBytes());
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testGetInstalledCaCerts_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testGetInstalledCaCerts_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.getInstalledCaCerts(mComponent);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testGetInstalledCaCerts_failIfNotCertInstaller() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testGetInstalledCaCerts_failIfNotCertInstaller");
+            return;
+        }
+        try {
+            // Delegated cert installer is identified by using null as the first argument.
+            mDevicePolicyManager.getInstalledCaCerts(null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testHasCaCertInstalled_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testHasCaCertInstalled_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.hasCaCertInstalled(mComponent,
+                    TEST_CA_STRING1.getBytes());
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testHasCaCertInstalled_failIfNotCertInstaller() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testHasCaCertInstalled_failIfNotCertInstaller");
+            return;
+        }
+        try {
+            // Delegated cert installer is identified by using null as the first argument.
+            mDevicePolicyManager.hasCaCertInstalled(null, TEST_CA_STRING1.getBytes());
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testUninstallAllUserCaCerts_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testUninstallAllUserCaCerts_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.uninstallAllUserCaCerts(mComponent);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testUninstallAllUserCaCerts_failIfNotCertInstaller() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testUninstallAllUserCaCerts_failIfNotCertInstaller");
+            return;
+        }
+        try {
+            // Delegated cert installer is identified by using null as the first argument.
+            mDevicePolicyManager.uninstallAllUserCaCerts(null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testSetScreenCaptureDisabled_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetScreenCaptureDisabled_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setScreenCaptureDisabled(mComponent, true);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetAutoTimeRequired_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetAutoTimeRequired_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setAutoTimeRequired(mComponent, true);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testAddPersistentPreferredActivity_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testAddPersistentPreferredActivity_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.addPersistentPreferredActivity(mComponent,
+                    new IntentFilter(Intent.ACTION_MAIN),
+                    new ComponentName("android.admin.cts", "dummy"));
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testClearPackagePersistentPreferredActivities_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testClearPackagePersistentPreferredActivities_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.clearPackagePersistentPreferredActivities(mComponent,
+                    "android.admin.cts");
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetApplicationRestrictions_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetApplicationRestrictions_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setApplicationRestrictions(mComponent,
+                    "android.admin.cts", null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testAddUserRestriction_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testAddUserRestriction_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.addUserRestriction(mComponent,
+                    UserManager.DISALLOW_SMS);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetAccountManagementDisabled_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetAccountManagementDisabled_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setAccountManagementDisabled(mComponent,
+                    "dummy", true);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetRestrictionsProvider_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetRestrictionsProvider_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setRestrictionsProvider(mComponent,
+                    new ComponentName("android.admin.cts", "dummy"));
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetUninstallBlocked_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetUninstallBlocked_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setUninstallBlocked(mComponent,
+                    "android.admin.cts", true);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetPermittedAccessibilityServices_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetPermittedAccessibilityServices_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setPermittedAccessibilityServices(mComponent, null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetBluetoothContactSharingDisabled_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetBluetoothContactSharingDisabled_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setBluetoothContactSharingDisabled(mComponent, true);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetPermittedInputMethods_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetPermittedInputMethods_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setPermittedInputMethods(mComponent, null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    /**
+     * Test whether the version of the pre-installed launcher is at least L. This is needed for
+     * managed profile support.
+     */
+    public void testLauncherVersionAtLeastL() throws Exception {
+        if (!mManagedProfiles) {
+            return;
+        }
+
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
+                0 /* default flags */);
+        assertFalse("No launcher present", resolveInfos.isEmpty());
+
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            ApplicationInfo launcherAppInfo = mPackageManager.getApplicationInfo(
+                    resolveInfo.activityInfo.packageName, 0 /* default flags */);
+            if ((launcherAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 &&
+                    launcherAppInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
+                return;
+            }
+        }
+        fail("No system launcher with version L+ present present on device.");
+    }
+
+    /**
+     * Test that managed provisioning is pre-installed if and only if the device declares the
+     * device admin feature.
+     */
+    public void testManagedProvisioningPreInstalled() throws Exception {
+        assertEquals(mDeviceAdmin, isPackageInstalledOnSystemImage(MANAGED_PROVISIONING_PKG));
+    }
+
+    private void assertDeviceOwnerMessage(String message) {
+        assertTrue("message is: "+ message, message.contains("does not own the device")
+                || message.contains("can only be called by the device owner"));
+    }
+
+    private void assertProfileOwnerMessage(String message) {
+        assertTrue("message is: "+ message,
+                message.contains("does not own the profile"));
+    }
+
+    private void resetComplexPasswordRestrictions() {
+        /**
+         * Not enough to reset only mComponent as
+         * {@link DevicePolicyManager#resetPassword(String, int)} checks restrictions across all
+         * admin components.
+         */
+        for (ComponentName adminComponent : new ComponentName[] {mComponent, mSecondComponent}) {
+            mDevicePolicyManager.setPasswordMinimumLength(adminComponent, 0);
+            mDevicePolicyManager.setPasswordMinimumUpperCase(adminComponent, 0);
+            mDevicePolicyManager.setPasswordMinimumLowerCase(adminComponent, 0);
+            mDevicePolicyManager.setPasswordMinimumLetters(adminComponent, 0);
+            mDevicePolicyManager.setPasswordMinimumNumeric(adminComponent, 0);
+            mDevicePolicyManager.setPasswordMinimumSymbols(adminComponent, 0);
+            mDevicePolicyManager.setPasswordMinimumNonLetter(adminComponent, 0);
+        }
+    }
+
+    private void assertPasswordFails(String password, String restriction) {
+        try {
+            boolean passwordResetResult = mDevicePolicyManager.resetPassword(password, /* flags= */0);
+            assertFalse("Password '" + password + "' should have failed on " + restriction,
+                    passwordResetResult);
+        } catch (IllegalArgumentException e) {
+            // yesss, we have failed!
+        }
+    }
+
+    private void assertPasswordSucceeds(String password, String restriction) {
+        boolean passwordResetResult = mDevicePolicyManager.resetPassword(password, /* flags= */0);
+        assertTrue("Password '" + password + "' failed on " + restriction, passwordResetResult);
+        assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
+    }
+
+    public void testSetDelegatedCertInstaller_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetDelegatedCertInstaller_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setCertInstallerPackage(mComponent, "com.test.package");
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testGetDelegatedCertInstaller_failIfNotProfileOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testGetDelegatedCertInstaller_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.getCertInstallerPackage(mComponent);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testSetSystemUpdatePolicy_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetSystemUpdatePolicy_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setSystemUpdatePolicy(mComponent, null);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    private boolean isPackageInstalledOnSystemImage(String packagename) {
+        try {
+            ApplicationInfo info = mPackageManager.getApplicationInfo(packagename,
+                    0 /* default flags */);
+            return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    public void testReboot_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testReboot_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.reboot(mComponent);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+}
diff --git a/tests/app/Android.mk b/tests/app/Android.mk
index f4f0a13..0acabaf 100644
--- a/tests/app/Android.mk
+++ b/tests/app/Android.mk
@@ -21,15 +21,23 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_PROGUARD_ENABLED := disabled
-
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common voip-common org.apache.http.legacy
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ctstestserver
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-              src/android/app/cts/ISecondary.aidl
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := CtsAppTestStubs
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
-include $(BUILD_CTS_SUPPORT_PACKAGE)
+LOCAL_PACKAGE_NAME := CtsAppTestCases
+
+LOCAL_INSTRUMENTATION_FOR := CtsAppTestStubs
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tests/app/AndroidManifest.xml b/tests/app/AndroidManifest.xml
index 8d7729e..0a7216d 100644
--- a/tests/app/AndroidManifest.xml
+++ b/tests/app/AndroidManifest.xml
@@ -16,270 +16,22 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.app.stub">
+    package="android.app.cts">
 
-    <permission android:name="android.app.cts.permission.TEST_GRANTED"
-        android:protectionLevel="normal"
-            android:label="@string/permlab_testGranted"
-            android:description="@string/permdesc_testGranted">
-        <meta-data android:name="android.app.cts.string" android:value="foo" />
-        <meta-data android:name="android.app.cts.boolean" android:value="true" />
-        <meta-data android:name="android.app.cts.integer" android:value="100" />
-        <meta-data android:name="android.app.cts.color" android:value="#ff000000" />
-        <meta-data android:name="android.app.cts.float" android:value="100.1" />
-        <meta-data android:name="android.app.cts.reference" android:resource="@xml/metadata" />
-    </permission>
-
-    <uses-permission android:name="android.app.cts.permission.TEST_GRANTED" />
-    <uses-permission android:name="android.permission.READ_CONTACTS" />
-    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-    <uses-permission android:name="android.permission.CAMERA" />
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
-    <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-sdk android:minSdkVersion="11" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.BODY_SENSORS" />
-
-    <application android:label="Android TestCase"
-                android:icon="@drawable/size_48x48"
-                android:maxRecents="1"
-                android:multiArch="true"
-                android:name="android.app.cts.MockApplication"
-                android:supportsRtl="true">
+    <application>
         <uses-library android:name="android.test.runner" />
         <uses-library android:name="org.apache.http.legacy" android:required="false" />
-
-        <activity android:name="android.app.cts.ActionBarActivity" />
-
-        <activity android:name="android.app.cts.DialogStubActivity"
-            android:label="DialogStubActivity"
-            android:configChanges="keyboardHidden|orientation|screenSize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="android.app.cts.MockActivity" android:label="MockActivity">
-            <meta-data android:name="android.app.alias"
-                android:resource="@xml/alias" />
-            <meta-data android:name="android.app.intent.filter"
-                android:resource="@xml/intentfilter" />
-        </activity>
-
-        <activity android:name="android.app.cts.MockApplicationActivity"
-            android:label="MockApplicationActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="android.app.cts.InstrumentationTestActivity"
-                  android:theme="@style/Theme_NoSwipeDismiss"
-                  android:label="InstrumentationTestActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:mimeType="vnd.android.cursor.dir/person" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="android.app.cts.AliasActivityStub">
-            <meta-data android:name="android.app.alias"
-                android:resource="@xml/alias" />
-        </activity>
-
-        <activity android:name="android.app.cts.ChildActivity"
-                        android:label="ChildActivity" />
-
-        <receiver android:name="android.app.cts.MockReceiver">
-            <intent-filter>
-                <action android:name="android.app.cts.PendingIntentTest.TEST_RECEIVER" />
-            </intent-filter>
-        </receiver>
-
-        <service android:name="android.app.cts.MockService" />
-
-        <activity android:name="android.app.cts.SearchManagerStubActivity"
-                android:label="SearchManagerStubActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.SEARCH" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-            <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
-        </activity>
-
-        <service android:name="android.app.cts.LocalService">
-            <intent-filter>
-                <action android:name="android.app.cts.activity.SERVICE_LOCAL" />
-            </intent-filter>
-            <meta-data android:name="android.app.cts.string" android:value="foo" />
-            <meta-data android:name="android.app.cts.boolean" android:value="true" />
-            <meta-data android:name="android.app.cts.integer" android:value="100" />
-            <meta-data android:name="android.app.cts.color" android:value="#ff000000" />
-            <meta-data android:name="android.app.cts.float" android:value="100.1" />
-            <meta-data android:name="android.app.cts.reference" android:resource="@xml/metadata" />
-        </service>
-
-        <service android:name="android.app.cts.LocalGrantedService"
-             android:permission="android.app.cts.permission.TEST_GRANTED">
-            <intent-filter>
-                <action android:name="android.app.cts.activity.SERVICE_LOCAL_GRANTED" />
-            </intent-filter>
-        </service>
-
-        <service android:name="android.app.cts.LocalDeniedService"
-               android:permission="android.app.cts.permission.TEST_DENIED">
-            <intent-filter>
-                <action android:name="android.app.cts.activity.SERVICE_LOCAL_DENIED" />
-            </intent-filter>
-        </service>
-
-        <activity android:name="android.app.cts.TestedScreen"
-                android:process=":remoteScreen">
-        </activity>
-        <activity android:name="android.app.cts.LocalScreen" android:multiprocess="true">
-        </activity>
-        <activity android:name="android.app.cts.ClearTop" android:multiprocess="true"
-               android:launchMode="singleTop">
-        </activity>
-        <activity android:name="android.app.cts.LocalDialog" android:multiprocess="true"
-               android:theme="@android:style/Theme.Dialog">
-        </activity>
-
-        <activity android:name="android.app.cts.PendingIntentStubActivity"
-             android:label="PendingIntentStubActivity"/>
-
-        <activity android:name="android.app.cts.LocalActivityManagerStubActivity"
-                        android:label="LocalActivityManagerStubActivity" />
-
-        <activity android:name="android.app.cts.LocalActivityManagerTestHelper"
-            android:label="LocalActivityManagerTestHelper" />
-
-        <activity android:name="android.app.cts.LaunchpadTabActivity" android:multiprocess="true">
-        </activity>
-
-        <activity android:name="android.app.cts.LocalActivity" android:multiprocess="true">
-            <meta-data android:name="android.app.cts.string" android:value="foo" />
-            <meta-data android:name="android.app.cts.boolean" android:value="true" />
-            <meta-data android:name="android.app.cts.integer" android:value="100" />
-            <meta-data android:name="android.app.cts.color" android:value="#ff000000" />
-            <meta-data android:name="android.app.cts.float" android:value="100.1" />
-            <meta-data android:name="android.app.cts.reference" android:resource="@xml/metadata" />
-        </activity>
-
-        <activity android:name="android.app.cts.TestedActivity"
-                android:process=":remoteActivity">
-        </activity>
-
-        <activity android:name="android.app.cts.ExpandableListTestActivity"
-            android:label="ExpandableListTestActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="android.app.cts.ChildTabActivity" android:label="ChildTabActivity" />
-
-        <activity android:name="android.app.cts.LauncherActivityStub"
-                  android:label="LauncherActivityStub" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="android.app.cts.MockTabActivity" android:label="MockTabActivity" />
-
-        <activity android:name="android.app.cts.AppStubActivity" android:label="AppStubActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="android.app.cts.DialogStubActivity"
-                  android:theme="@style/Theme_NoSwipeDismiss"
-                  android:label="DialogStubActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="android.app.cts.ActivityManagerStubFooActivity"
-            android:label="ActivityManagerStubFooActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="android.app.cts.ActivityManagerRecentOneActivity"
-            android:label="ActivityManagerRecentOneActivity"
-            android:allowTaskReparenting="true"
-            android:taskAffinity="android.app.cts.recentOne">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="android.app.cts.ActivityManagerRecentTwoActivity"
-            android:label="ActivityManagerRecentTwoActivity"
-            android:allowTaskReparenting="true"
-            android:taskAffinity="android.app.cts.recentTwo">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="android.app.cts.ActivityManagerStubCrashActivity"
-            android:label="ActivityManagerStubCrashActivity"
-            android:multiprocess="true"
-            android:process=":ActivityManagerStubCrashActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <service android:name="android.app.cts.StubRemoteService"
-            android:process=":remote">
-            <intent-filter>
-                <action
-                    android:name="android.app.cts.ISecondary" />
-                <action
-                    android:name="android.app.REMOTESERVICE" />
-            </intent-filter>
-        </service>
-
-        <activity android:name="android.app.ActivityGroup"
-            android:label="ActivityGroup" />
-
-        <activity android:name="android.app.cts.KeyguardManagerActivity"
-            android:label="KeyguardManagerActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-            </intent-filter>
-        </activity>
-
-        <service android:name="android.app.cts.IntentServiceStub"/>
-
-        <activity android:name="android.app.cts.LaunchpadActivity"
-                  android:configChanges="keyboardHidden|orientation|screenSize"
-                  android:multiprocess="true">
-        </activity>
-
-        <activity android:name="android.app.cts.ActivityManagerMemoryClassLaunchActivity" />
-
-        <activity android:name="android.app.cts.ActivityManagerMemoryClassTestActivity"
-                android:process=":memoryclass" />
-
     </application>
 
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.app.stubs"
+                     android:label="CTS tests of android.app">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
 </manifest>
 
diff --git a/tests/app/AndroidTest.xml b/tests/app/AndroidTest.xml
new file mode 100644
index 0000000..acbc9e7
--- /dev/null
+++ b/tests/app/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS App test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSimpleApp.apk" />
+        <option name="test-file-name" value="CtsAppTestStubs.apk" />
+        <option name="test-file-name" value="CtsAppTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.app.cts" />
+        <option name="runtime-hint" value="3m8s" />
+    </test>
+
+</configuration>
diff --git a/tests/tests/app/AndroidTest.xml b/tests/app/OldAndroidTest.xml
similarity index 100%
rename from tests/tests/app/AndroidTest.xml
rename to tests/app/OldAndroidTest.xml
diff --git a/tests/app/app/Android.mk b/tests/app/app/Android.mk
new file mode 100644
index 0000000..a638b70
--- /dev/null
+++ b/tests/app/app/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common voip-common org.apache.http.legacy
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ctstestserver
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+              src/android/app/stubs/ISecondary.aidl
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_PACKAGE_NAME := CtsAppTestStubs
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
new file mode 100644
index 0000000..c45bb2f
--- /dev/null
+++ b/tests/app/app/AndroidManifest.xml
@@ -0,0 +1,326 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.app.stubs">
+
+    <permission android:name="android.app.stubs.permission.TEST_GRANTED"
+        android:protectionLevel="normal"
+            android:label="@string/permlab_testGranted"
+            android:description="@string/permdesc_testGranted">
+        <meta-data android:name="android.app.stubs.string" android:value="foo" />
+        <meta-data android:name="android.app.stubs.boolean" android:value="true" />
+        <meta-data android:name="android.app.stubs.integer" android:value="100" />
+        <meta-data android:name="android.app.stubs.color" android:value="#ff000000" />
+        <meta-data android:name="android.app.stubs.float" android:value="100.1" />
+        <meta-data android:name="android.app.stubs.reference" android:resource="@xml/metadata" />
+    </permission>
+
+    <uses-permission android:name="android.app.stubs.permission.TEST_GRANTED" />
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.BODY_SENSORS" />
+
+    <application android:label="Android TestCase"
+                android:icon="@drawable/size_48x48"
+                android:maxRecents="1"
+                android:multiArch="true"
+                android:name="android.app.stubs.MockApplication"
+                android:supportsRtl="true">
+        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
+
+        <activity android:name="android.app.stubs.ActionBarActivity" />
+
+        <activity android:name="android.app.stubs.DialogStubActivity"
+            android:label="DialogStubActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.MockActivity" android:label="MockActivity">
+            <meta-data android:name="android.app.alias"
+                android:resource="@xml/alias" />
+            <meta-data android:name="android.app.intent.filter"
+                android:resource="@xml/intentfilter" />
+        </activity>
+
+        <activity android:name="android.app.stubs.MockApplicationActivity"
+            android:label="MockApplicationActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.InstrumentationTestActivity"
+                  android:theme="@style/Theme_NoSwipeDismiss"
+                  android:label="InstrumentationTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/person" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.AliasActivityStub">
+            <meta-data android:name="android.app.alias"
+                android:resource="@xml/alias" />
+        </activity>
+
+        <activity android:name="android.app.stubs.ChildActivity"
+                        android:label="ChildActivity" />
+
+        <receiver android:name="android.app.stubs.MockReceiver">
+            <intent-filter>
+                <action android:name="android.app.stubs.PendingIntentTest.TEST_RECEIVER" />
+            </intent-filter>
+        </receiver>
+
+        <service android:name="android.app.stubs.MockService" />
+
+        <activity android:name="android.app.stubs.SearchManagerStubActivity"
+                android:label="SearchManagerStubActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.SEARCH" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
+        </activity>
+
+        <service android:name="android.app.stubs.LocalService">
+            <intent-filter>
+                <action android:name="android.app.stubs.activity.SERVICE_LOCAL" />
+            </intent-filter>
+            <meta-data android:name="android.app.stubs.string" android:value="foo" />
+            <meta-data android:name="android.app.stubs.boolean" android:value="true" />
+            <meta-data android:name="android.app.stubs.integer" android:value="100" />
+            <meta-data android:name="android.app.stubs.color" android:value="#ff000000" />
+            <meta-data android:name="android.app.stubs.float" android:value="100.1" />
+            <meta-data android:name="android.app.stubs.reference" android:resource="@xml/metadata" />
+        </service>
+
+        <service android:name="android.app.stubs.LocalGrantedService"
+             android:permission="android.app.stubs.permission.TEST_GRANTED">
+            <intent-filter>
+                <action android:name="android.app.stubs.activity.SERVICE_LOCAL_GRANTED" />
+            </intent-filter>
+        </service>
+
+        <service android:name="android.app.stubs.LocalDeniedService"
+               android:permission="android.app.stubs.permission.TEST_DENIED">
+            <intent-filter>
+                <action android:name="android.app.stubs.activity.SERVICE_LOCAL_DENIED" />
+            </intent-filter>
+        </service>
+
+        <activity android:name="android.app.stubs.TestedScreen"
+                android:process=":remoteScreen">
+        </activity>
+        <activity android:name="android.app.stubs.LocalScreen" android:multiprocess="true">
+        </activity>
+        <activity android:name="android.app.stubs.ClearTop" android:multiprocess="true"
+               android:launchMode="singleTop">
+        </activity>
+        <activity android:name="android.app.stubs.LocalDialog" android:multiprocess="true"
+               android:theme="@android:style/Theme.Dialog">
+        </activity>
+
+        <activity android:name="android.app.stubs.PendingIntentStubActivity"
+             android:label="PendingIntentStubActivity"/>
+
+        <activity android:name="android.app.stubs.LocalActivityManagerStubActivity"
+                        android:label="LocalActivityManagerStubActivity" />
+
+        <activity android:name="android.app.stubs.LocalActivityManagerTestHelper"
+            android:label="LocalActivityManagerTestHelper" />
+
+        <activity android:name="android.app.stubs.LaunchpadTabActivity" android:multiprocess="true">
+        </activity>
+
+        <activity android:name="android.app.stubs.LocalActivity" android:multiprocess="true">
+            <meta-data android:name="android.app.stubs.string" android:value="foo" />
+            <meta-data android:name="android.app.stubs.boolean" android:value="true" />
+            <meta-data android:name="android.app.stubs.integer" android:value="100" />
+            <meta-data android:name="android.app.stubs.color" android:value="#ff000000" />
+            <meta-data android:name="android.app.stubs.float" android:value="100.1" />
+            <meta-data android:name="android.app.stubs.reference" android:resource="@xml/metadata" />
+        </activity>
+
+        <activity android:name="android.app.stubs.TestedActivity"
+                android:process=":remoteActivity">
+        </activity>
+
+        <activity android:name="android.app.stubs.ExpandableListTestActivity"
+            android:label="ExpandableListTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.FragmentTestActivity"
+            android:label="FragmentTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.ChildTabActivity" android:label="ChildTabActivity" />
+
+        <activity android:name="android.app.stubs.LauncherActivityStub"
+                  android:label="LauncherActivityStub" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.MockTabActivity" android:label="MockTabActivity" />
+
+        <activity android:name="android.app.stubs.AppStubActivity" android:label="AppStubActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.DialogStubActivity"
+                  android:theme="@style/Theme_NoSwipeDismiss"
+                  android:label="DialogStubActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.ActivityManagerStubFooActivity"
+            android:label="ActivityManagerStubFooActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.ActivityManagerRecentOneActivity"
+            android:label="ActivityManagerRecentOneActivity"
+            android:allowTaskReparenting="true"
+            android:taskAffinity="android.app.stubs.recentOne">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.ActivityManagerRecentTwoActivity"
+            android:label="ActivityManagerRecentTwoActivity"
+            android:allowTaskReparenting="true"
+            android:taskAffinity="android.app.stubs.recentTwo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.ActivityManagerStubCrashActivity"
+            android:label="ActivityManagerStubCrashActivity"
+            android:multiprocess="true"
+            android:process=":ActivityManagerStubCrashActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+
+        <service android:name="android.app.stubs.StubRemoteService"
+            android:process=":remote">
+            <intent-filter>
+                <action
+                    android:name="android.app.stubs.ISecondary" />
+                <action
+                    android:name="android.app.REMOTESERVICE" />
+            </intent-filter>
+        </service>
+
+        <activity android:name="android.app.ActivityGroup"
+            android:label="ActivityGroup" />
+
+        <activity android:name="android.app.stubs.KeyguardManagerActivity"
+            android:label="KeyguardManagerActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <service android:name="android.app.stubs.IntentServiceStub"/>
+
+        <activity android:name="android.app.stubs.LaunchpadActivity"
+                  android:configChanges="keyboardHidden|orientation|screenSize"
+                  android:multiprocess="true">
+        </activity>
+
+        <activity android:name="android.app.stubs.ActivityManagerMemoryClassLaunchActivity" />
+
+        <activity android:name="android.app.stubs.ActivityManagerMemoryClassTestActivity"
+                android:process=":memoryclass" />
+
+        <activity android:name="android.app.stubs.PipActivity"
+                  android:label="PipActivity"
+                  android:resizeable="true"
+                  android:supportsPictureInPicture="true"
+                  android:configChanges="smallestScreenSize|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.PipNotResizeableActivity"
+                  android:label="PipNotResizeableActivity"
+                  android:resizeable="false"
+                  android:supportsPictureInPicture="true"
+                  android:configChanges="smallestScreenSize|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.PipNotSupportedActivity"
+                  android:label="PipNotSupportedActivity"
+                  android:resizeable="true"
+                  android:supportsPictureInPicture="false"
+                  android:configChanges="smallestScreenSize|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>
+
diff --git a/tests/app/assets/noiseandchirps b/tests/app/app/assets/noiseandchirps
similarity index 100%
rename from tests/app/assets/noiseandchirps
rename to tests/app/app/assets/noiseandchirps
Binary files differ
diff --git a/tests/app/assets/noiseandchirps.mp3 b/tests/app/app/assets/noiseandchirps.mp3
similarity index 100%
rename from tests/app/assets/noiseandchirps.mp3
rename to tests/app/app/assets/noiseandchirps.mp3
Binary files differ
diff --git a/tests/app/assets/noiseandchirps.ogg b/tests/app/app/assets/noiseandchirps.ogg
similarity index 100%
rename from tests/app/assets/noiseandchirps.ogg
rename to tests/app/app/assets/noiseandchirps.ogg
Binary files differ
diff --git a/tests/app/assets/noiseandchirps.wrong b/tests/app/app/assets/noiseandchirps.wrong
similarity index 100%
rename from tests/app/assets/noiseandchirps.wrong
rename to tests/app/app/assets/noiseandchirps.wrong
Binary files differ
diff --git a/tests/app/res/drawable/icon_black.jpg b/tests/app/app/res/drawable/icon_black.jpg
similarity index 100%
rename from tests/app/res/drawable/icon_black.jpg
rename to tests/app/app/res/drawable/icon_black.jpg
Binary files differ
diff --git a/tests/app/res/drawable/icon_blue.jpg b/tests/app/app/res/drawable/icon_blue.jpg
similarity index 100%
rename from tests/app/res/drawable/icon_blue.jpg
rename to tests/app/app/res/drawable/icon_blue.jpg
Binary files differ
diff --git a/tests/app/res/drawable/icon_green.jpg b/tests/app/app/res/drawable/icon_green.jpg
similarity index 100%
rename from tests/app/res/drawable/icon_green.jpg
rename to tests/app/app/res/drawable/icon_green.jpg
Binary files differ
diff --git a/tests/app/res/drawable/icon_red.jpg b/tests/app/app/res/drawable/icon_red.jpg
similarity index 100%
rename from tests/app/res/drawable/icon_red.jpg
rename to tests/app/app/res/drawable/icon_red.jpg
Binary files differ
diff --git a/tests/app/res/drawable/icon_yellow.jpg b/tests/app/app/res/drawable/icon_yellow.jpg
similarity index 100%
rename from tests/app/res/drawable/icon_yellow.jpg
rename to tests/app/app/res/drawable/icon_yellow.jpg
Binary files differ
diff --git a/tests/app/res/drawable/ninepatch_0.9.png b/tests/app/app/res/drawable/ninepatch_0.9.png
similarity index 100%
rename from tests/app/res/drawable/ninepatch_0.9.png
rename to tests/app/app/res/drawable/ninepatch_0.9.png
Binary files differ
diff --git a/tests/app/res/drawable/ninepatch_1.9.png b/tests/app/app/res/drawable/ninepatch_1.9.png
similarity index 100%
rename from tests/app/res/drawable/ninepatch_1.9.png
rename to tests/app/app/res/drawable/ninepatch_1.9.png
Binary files differ
diff --git a/tests/app/res/drawable/pass.jpg b/tests/app/app/res/drawable/pass.jpg
similarity index 100%
rename from tests/app/res/drawable/pass.jpg
rename to tests/app/app/res/drawable/pass.jpg
Binary files differ
diff --git a/tests/app/res/drawable/robot.png b/tests/app/app/res/drawable/robot.png
similarity index 100%
rename from tests/app/res/drawable/robot.png
rename to tests/app/app/res/drawable/robot.png
Binary files differ
diff --git a/tests/app/res/drawable/size_48x48.jpg b/tests/app/app/res/drawable/size_48x48.jpg
similarity index 100%
rename from tests/app/res/drawable/size_48x48.jpg
rename to tests/app/app/res/drawable/size_48x48.jpg
Binary files differ
diff --git a/tests/app/app/res/layout/activity_content.xml b/tests/app/app/res/layout/activity_content.xml
new file mode 100644
index 0000000..8870e60
--- /dev/null
+++ b/tests/app/app/res/layout/activity_content.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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:id="@+id/content"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"/>
diff --git a/tests/app/res/layout/alert_dialog_text_entry.xml b/tests/app/app/res/layout/alert_dialog_text_entry.xml
similarity index 100%
rename from tests/app/res/layout/alert_dialog_text_entry.xml
rename to tests/app/app/res/layout/alert_dialog_text_entry.xml
diff --git a/tests/app/res/layout/alert_dialog_text_entry_2.xml b/tests/app/app/res/layout/alert_dialog_text_entry_2.xml
similarity index 100%
rename from tests/app/res/layout/alert_dialog_text_entry_2.xml
rename to tests/app/app/res/layout/alert_dialog_text_entry_2.xml
diff --git a/tests/app/res/layout/alertdialog_custom_title.xml b/tests/app/app/res/layout/alertdialog_custom_title.xml
similarity index 100%
rename from tests/app/res/layout/alertdialog_custom_title.xml
rename to tests/app/app/res/layout/alertdialog_custom_title.xml
diff --git a/tests/app/res/layout/app_activity.xml b/tests/app/app/res/layout/app_activity.xml
similarity index 100%
rename from tests/app/res/layout/app_activity.xml
rename to tests/app/app/res/layout/app_activity.xml
diff --git a/tests/app/res/layout/checkbox_layout.xml b/tests/app/app/res/layout/checkbox_layout.xml
similarity index 100%
rename from tests/app/res/layout/checkbox_layout.xml
rename to tests/app/app/res/layout/checkbox_layout.xml
diff --git a/tests/app/res/layout/dialog_stub_layout.xml b/tests/app/app/res/layout/dialog_stub_layout.xml
similarity index 100%
rename from tests/app/res/layout/dialog_stub_layout.xml
rename to tests/app/app/res/layout/dialog_stub_layout.xml
diff --git a/tests/app/app/res/layout/fragment_end.xml b/tests/app/app/res/layout/fragment_end.xml
new file mode 100644
index 0000000..aa3d9e8
--- /dev/null
+++ b/tests/app/app/res/layout/fragment_end.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+    <TextView android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:transitionName="destination"
+              android:id="@+id/hello"
+              android:text="@string/hello"/>
+    <View android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#0F0"
+          android:id="@+id/greenSquare"/>
+    <View android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#F00"
+          android:id="@+id/redSquare"/>
+</LinearLayout>
diff --git a/tests/app/app/res/layout/fragment_start.xml b/tests/app/app/res/layout/fragment_start.xml
new file mode 100644
index 0000000..793e9b5
--- /dev/null
+++ b/tests/app/app/res/layout/fragment_start.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+    <View android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#0F0"
+          android:id="@+id/greenSquare"/>
+    <View android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#F00"
+          android:id="@+id/redSquare"/>
+    <TextView android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:transitionName="source"
+              android:id="@+id/hello"
+              android:text="@string/hello"/>
+</LinearLayout>
diff --git a/tests/app/res/menu/browser.xml b/tests/app/app/res/menu/browser.xml
similarity index 100%
rename from tests/app/res/menu/browser.xml
rename to tests/app/app/res/menu/browser.xml
diff --git a/tests/app/res/values/arrays.xml b/tests/app/app/res/values/arrays.xml
similarity index 100%
rename from tests/app/res/values/arrays.xml
rename to tests/app/app/res/values/arrays.xml
diff --git a/tests/app/res/values/attrs.xml b/tests/app/app/res/values/attrs.xml
similarity index 100%
rename from tests/app/res/values/attrs.xml
rename to tests/app/app/res/values/attrs.xml
diff --git a/tests/app/res/values/colors.xml b/tests/app/app/res/values/colors.xml
similarity index 100%
rename from tests/app/res/values/colors.xml
rename to tests/app/app/res/values/colors.xml
diff --git a/tests/app/app/res/values/strings.xml b/tests/app/app/res/values/strings.xml
new file mode 100644
index 0000000..5e9e6d7
--- /dev/null
+++ b/tests/app/app/res/values/strings.xml
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="permlab_testGranted">Test Granted</string>
+    <string name="permdesc_testGranted">Used for running CTS tests, for testing operations
+        where we have the permission.</string>
+    <string name="permlab_testDynamic">Test Dynamic</string>
+    <string name="permdesc_testDynamic">Used for running CTS tests, for testing adding
+        dynamic permissions.</string>
+    <string name="permlab_testDenied">Test Denied</string>
+    <string name="permdesc_testDenied">Used for running CTS tests, for testing operations
+        where we do not have the permission.</string>
+    <string name="explain">1. click start. \n2. if above image shaked, then press pass button,
+         else press failed button.</string>
+    <string name="text_view_hello">Hello! Text view!</string>
+    <string name="text_view_hello_two_lines">Hello! \nText view!</string>
+    <string name="text_view_simple_hint">This is a hint.</string>
+    <string name="text_view_hint">This is a string for testing hint of textview.</string>
+    <string name="activity_forwarding">App/Forwarding</string>
+    <string name="forwarding">$$$</string>
+    <string name="go">Go</string>
+    <string name="back">Back</string>
+    <string name="forward_target">
+        Press back button and notice we don\'t see the previous activity.
+    </string>
+    <string name="edit_text">testing</string>
+    <string name="text">DialogTest</string>
+    <string name="text_country">Country</string>
+    <string name="text_name">Name</string>
+    <string name="hello_world">Hello, World!</string>
+    <string name="hello_android">Hello, Android!</string>
+    <string name="alert_dialog_username">Name:</string>
+    <string name="alert_dialog_password">Password:</string>
+    <string name="alert_dialog_positive">Positive</string>
+    <string name="alert_dialog_negative">Negative</string>
+    <string name="alert_dialog_neutral">Neutral</string>
+    <string name="notify">Notify </string>
+    <string name="tabs_1">testing</string>
+    <string name="table_layout_first">first</string>
+    <string name="table_layout_second">second</string>
+    <string name="table_layout_third">third</string>
+    <string name="table_layout_long">Very long to make the string out of the screen</string>
+    <string name="chronometer_text">Test Chronometer</string>
+    <string name="am">AM</string>
+    <string name="pm">PM</string>
+    <string name="viewgroup_test">ViewGroup test</string>
+    <string name="viewanimator_test">ViewAnimator test</string>
+    <string name="id_ok">OK</string>
+    <string name="id_cancel">Cancel</string>
+    <string name="context_test_string1">This is %s string.</string>
+    <string name="context_test_string2">This is test string.</string>
+    <string name="animationutils_test_instructions">Choose different animations</string>
+    <string name="animationutils_test_alpha">Alpha animation</string>
+    <string name="animationutils_test_scale">Scale animation</string>
+    <string name="animationutils_test_rotate">Rotate animation</string>
+    <string name="animationutils_test_translate">Translate animation</string>
+    <string name="animationutils_test_set">Animation set</string>
+    <string name="animationutils_test_layout">Layout animation</string>
+    <string name="animationutils_test_gridlayout">Grid layout animation</string>
+    <string name="twolinelistitem_test_text1">text1</string>
+    <string name="twolinelistitem_test_text2">text2</string>
+    <string name="metadata_text">metadata text</string>
+    <string name="horizontal_text_1">horizontal 1</string>
+    <string name="horizontal_text_2">horizontal 2</string>
+    <string name="horizontal_text_3">horizontal 3</string>
+    <string name="vertical_text_1">vertical 1</string>
+    <string name="vertical_text_2">vertical 2</string>
+    <string name="vertical_text_3">vertical 3</string>
+    <string name="reference">here</string>
+    <string name="coerceIntegerToString">100</string>
+    <string name="coerceBooleanToString">true</string>
+    <string name="coerceColorToString">#fff</string>
+    <string name="coerceFloatToString">100.0</string>
+    <string name="coerceDimensionToString">100px</string>
+    <string name="coerceFractionToString">100<xliff:g id="percent">%</xliff:g></string>
+    <string name="formattedStringNone">Format[]</string>
+    <string name="formattedStringOne">Format[<xliff:g id="format">%d</xliff:g>]</string>
+    <string name="formattedStringTwo">Format[<xliff:g id="format">%3$d,%2$s</xliff:g>]</string>
+    <string name="checkboxpref_key">checkboxpref_key</string>
+   <string name="checkboxpref_title">title of preference</string>
+   <string name="checkboxpref_summary">summary of preference</string>
+   <string name="checkboxpref_summary_on">summary on of preference</string>
+   <string name="checkboxpref_summary_off">summary off of preference</string>
+   <string name="checkboxpref_depend">checkboxpref_depend</string>
+   <string name="checkboxpref_depend_title"> depend title of preference</string>
+   <string name="checkboxpref_depend_summary"> depend summary of preference</string>
+   <string name="edittextpref_key">edittextpref_key</string>
+   <string name="edittextpref_default_value">default value of preference</string>
+   <string name="edittextpref_title">title of edit text preference</string>
+   <string name="edittextpref_summary">summary of edit text preference</string>
+   <string name="edittextpref_dialog_title">dialog title of edit text preference</string>
+   <string name="edittextpref_text">text of  edit text preference</string>
+   <string name="listpref_key">listpref_key</string>
+   <string name="listpref_title">title of list preference</string>
+   <string name="listpref_summary">summary of list preference</string>
+   <string name="listpref_dialogtitle">dialog title of list preference</string>
+   <string name="easy">Easy</string>
+   <string name="medium">Medium</string>
+   <string name="hard">Hard</string>
+   <string name="footer_view">Footer view</string>
+   <string name="header_view">Header view</string>
+   <string name="dialogpref_title">title of dialog preference </string>
+   <string name="dialogpref_dialog_title">dialog title of dialog preference </string>
+   <string name="dialogpref_key">dialogpref_key</string>
+   <string name="dialogpref_default_value">default value of dialog preference</string>
+   <string name="dialogpref_summary">summary of dialog preference</string>
+   <string name="dialogpref_message">message of dialog preference</string>
+   <string name="dialogpref_sure">Sure</string>
+   <string name="dialogpref_cancel">Cancel</string>
+   <string name="pref_key">pref_key</string>
+   <string name="pref_title">title of preference</string>
+   <string name="pref_summary">summary of preference</string>
+   <string name="pref_depend_key">pref_depend_key</string>
+   <string name="pref_depend_title"> depend title of preference</string>
+   <string name="pref_depend_summary"> depend summary of preference</string>
+   <string name="android_intent_action_preference">android.intent.action.PREFERENCE</string>
+   <string name="def_pref_key">def_pref_key</string>
+   <string name="def_pref_title">default preference</string>
+   <string name="def_pref_summary">This is default preference of cts</string>
+   <string name="relative_view1">view 1</string>
+   <string name="relative_view2">view 2</string>
+   <string name="relative_view3">view 3</string>
+   <string name="relative_view4">view 4</string>
+   <string name="relative_view5">view 5</string>
+   <string name="relative_view6">view 6</string>
+   <string name="relative_view7">view 7</string>
+   <string name="relative_view8">view 8</string>
+   <string name="relative_view9">view 9</string>
+   <string name="relative_view10">view 10</string>
+   <string name="relative_view11">view 11</string>
+   <string name="relative_view12">view 12</string>
+   <string name="relative_view13">view 13</string>
+   <string name="country">Country:</string>
+   <string name="symbol">Symbol:</string>
+   <string name="country_warning">No such country registered</string>
+   <string name="version_cur">base</string>
+   <string name="version_old">base</string>
+   <string name="version_v3">base</string>
+   <string name="authenticator_label">Android CTS</string>
+   <string name="search_label">Android CTS</string>
+   <string name="tag1">tag 1</string>
+   <string name="tag2">tag 2</string>
+
+   <string name="button">Button</string>
+   <string name="holo_test">Holo Test</string>
+   <string name="holo_generator">Holo Generator</string>
+   <string name="holo_light_test">Holo Light Test</string>
+   <string name="holo_light_generator">Holo Light Generator</string>
+   <string name="reference_image">Reference Image: </string>
+   <string name="generated_image">Generated Image: </string>
+   <string name="themes_prompt">Select a Theme:</string>
+   <string name="sample_text">Sample text goes here. I wanted something creative and whimsical
+but then I just got bored...</string>
+    <string name="long_text">This is a really long string which exceeds the width of the view.
+New devices have a much larger screen which actually enables long strings to be displayed
+with no fading. I have made this string longer to fix this case. If you are correcting this
+text, I would love to see the kind of devices you guys now use! Guys, maybe some devices need longer string!
+I think so, so how about double this string, like copy and paste!
+This is a really long string which exceeds the width of the view.
+New devices have a much larger screen which actually enables long strings to be displayed
+with no fading. I have made this string longer to fix this case. If you are correcting this
+text, I would love to see the kind of devices you guys now use! Guys, maybe some devices need longer string!
+I think so, so how about double this string, like copy and paste! </string>
+    <string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string>
+    <string name="hello">Hello World</string>
+</resources>
diff --git a/tests/app/res/values/styles.xml b/tests/app/app/res/values/styles.xml
similarity index 100%
rename from tests/app/res/values/styles.xml
rename to tests/app/app/res/values/styles.xml
diff --git a/tests/app/app/res/xml/alias.xml b/tests/app/app/res/xml/alias.xml
new file mode 100644
index 0000000..de3f557
--- /dev/null
+++ b/tests/app/app/res/xml/alias.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2008 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.
+ */
+-->
+
+<alias xmlns:android="http://schemas.android.com/apk/res/android">
+    <intent android:action="android.intent.action.MAIN"
+        android:targetPackage="android.app.stubs"
+        android:targetClass="android.app.stubs.ChildActivity"
+        android:data="http://www.google.com/">
+    </intent>
+</alias>
+
diff --git a/tests/app/res/xml/intentfilter.xml b/tests/app/app/res/xml/intentfilter.xml
similarity index 100%
rename from tests/app/res/xml/intentfilter.xml
rename to tests/app/app/res/xml/intentfilter.xml
diff --git a/tests/app/res/xml/metadata.xml b/tests/app/app/res/xml/metadata.xml
similarity index 100%
rename from tests/app/res/xml/metadata.xml
rename to tests/app/app/res/xml/metadata.xml
diff --git a/tests/app/res/xml/searchable.xml b/tests/app/app/res/xml/searchable.xml
similarity index 100%
rename from tests/app/res/xml/searchable.xml
rename to tests/app/app/res/xml/searchable.xml
diff --git a/tests/app/app/src/android/app/stubs/ActionBarActivity.java b/tests/app/app/src/android/app/stubs/ActionBarActivity.java
new file mode 100644
index 0000000..ec27b1b
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ActionBarActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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 android.app.stubs;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.os.Bundle;
+
+public class ActionBarActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        ActionBar bar = getActionBar();
+        if (bar != null) {
+            bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+        }
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/ActivityManagerMemoryClassLaunchActivity.java b/tests/app/app/src/android/app/stubs/ActivityManagerMemoryClassLaunchActivity.java
new file mode 100644
index 0000000..d79467c
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ActivityManagerMemoryClassLaunchActivity.java
@@ -0,0 +1,73 @@
+/*
+ * 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 android.app.stubs;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@link Activity} that just launches {@link ActivityManagerMemoryClassTestActivity} and
+ * returns the result of that activity.
+ */
+public class ActivityManagerMemoryClassLaunchActivity extends Activity {
+
+    public static final String MEMORY_CLASS_EXTRA = "activityMemoryClass";
+
+    private static final int TEST_ACTIVITY_REQUEST_CODE = 1337;
+
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+
+    private int mChildResult = RESULT_CANCELED;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Start the activity that runs in a separate process to do the actual testing,
+        // since the test itself cannot start an activity in a separate process. A separate
+        // process is used to avoid including the overhead of the test instrumentation process.
+
+        Intent intent = getIntent();
+        int memoryClass = intent.getIntExtra(MEMORY_CLASS_EXTRA, -1);
+
+        Intent testIntent = new Intent(this, ActivityManagerMemoryClassTestActivity.class);
+        testIntent.putExtra(MEMORY_CLASS_EXTRA, memoryClass);
+        startActivityForResult(testIntent, TEST_ACTIVITY_REQUEST_CODE);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (requestCode == 1337) {
+            synchronized (this) {
+                mChildResult = resultCode;
+            }
+        } else {
+            throw new IllegalStateException("Request code: " + requestCode);
+        }
+    }
+
+    public int getResult() throws InterruptedException {
+        mLatch.await(5, TimeUnit.SECONDS);
+        synchronized (this) {
+            return mChildResult;
+        }
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/ActivityManagerMemoryClassTestActivity.java b/tests/app/app/src/android/app/stubs/ActivityManagerMemoryClassTestActivity.java
new file mode 100644
index 0000000..09566aa
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ActivityManagerMemoryClassTestActivity.java
@@ -0,0 +1,75 @@
+/*
+ * 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 android.app.stubs;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * {@link Activity} that allocates arrays of 256k until reaching 75% of the specified memory class.
+ */
+public class ActivityManagerMemoryClassTestActivity extends Activity {
+
+    private static final String TAG = "ActivityManagerMemoryClassTest";
+
+    private static final double FREE_MEMORY_PERCENTAGE = 0.75;
+
+    private static final int ARRAY_BYTES_SIZE = 256 * 1024;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = getIntent();
+        int memoryClass =
+                intent.getIntExtra(ActivityManagerMemoryClassLaunchActivity.MEMORY_CLASS_EXTRA, -1);
+        new AllocateMemoryTask(memoryClass).execute();
+    }
+
+    private class AllocateMemoryTask extends AsyncTask<Void, Void, Void> {
+
+        private final int mMemoryClass;
+
+        AllocateMemoryTask(int memoryClass) {
+            this.mMemoryClass = memoryClass;
+        }
+
+        @Override
+        protected Void doInBackground(Void... params) {
+            int targetMbs = (int) (mMemoryClass * FREE_MEMORY_PERCENTAGE);
+            int numArrays = targetMbs * 1024 * 1024 / ARRAY_BYTES_SIZE;
+            Log.i(TAG, "Memory class: " + mMemoryClass + "mb Target memory: "
+                    + targetMbs + "mb Number of arrays: " + numArrays);
+
+            byte[][] arrays = new byte[numArrays][];
+            for (int i = 0; i < arrays.length; i++) {
+                Log.i(TAG, "Allocating array " + i + " of " + arrays.length
+                        + " (" + (i * ARRAY_BYTES_SIZE / 1024 / 1024) + "mb)");
+                arrays[i] = new byte[ARRAY_BYTES_SIZE];
+            }
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(Void result) {
+            super.onPostExecute(result);
+            setResult(RESULT_OK);
+            finish();
+        }
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/ActivityManagerRecentOneActivity.java b/tests/app/app/src/android/app/stubs/ActivityManagerRecentOneActivity.java
new file mode 100644
index 0000000..41944bd
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ActivityManagerRecentOneActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+
+public class ActivityManagerRecentOneActivity extends Activity {
+}
diff --git a/tests/app/app/src/android/app/stubs/ActivityManagerRecentTwoActivity.java b/tests/app/app/src/android/app/stubs/ActivityManagerRecentTwoActivity.java
new file mode 100644
index 0000000..136e565
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ActivityManagerRecentTwoActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+
+public class ActivityManagerRecentTwoActivity extends Activity {
+}
diff --git a/tests/app/app/src/android/app/stubs/ActivityManagerStubCrashActivity.java b/tests/app/app/src/android/app/stubs/ActivityManagerStubCrashActivity.java
new file mode 100644
index 0000000..f6bef49
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ActivityManagerStubCrashActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class ActivityManagerStubCrashActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        final TextView tv = new TextView(this);
+        tv.setText("Hello, Android but crash");
+        setContentView(tv);
+        die();
+    }
+
+    public void die() {
+        throw new NullPointerException("Expected NPE.");
+    }
+}
+
diff --git a/tests/app/app/src/android/app/stubs/ActivityManagerStubFooActivity.java b/tests/app/app/src/android/app/stubs/ActivityManagerStubFooActivity.java
new file mode 100644
index 0000000..5892e6b
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ActivityManagerStubFooActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class ActivityManagerStubFooActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        final TextView tv = new TextView(this);
+        tv.setText("Hello, Android");
+        setContentView(tv);
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/ActivityTestsBase.java b/tests/app/app/src/android/app/stubs/ActivityTestsBase.java
new file mode 100644
index 0000000..12463b4
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ActivityTestsBase.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.test.AndroidTestCase;
+import android.test.PerformanceTestCase;
+
+public class ActivityTestsBase extends AndroidTestCase implements PerformanceTestCase,
+        LaunchpadActivity.CallingTest {
+    public static final String PERMISSION_GRANTED = "android.app.cts.permission.TEST_GRANTED";
+    public static final String PERMISSION_DENIED = "android.app.cts.permission.TEST_DENIED";
+
+    private static final int TIMEOUT_MS = 60 * 1000;
+
+    protected Intent mIntent;
+
+    private PerformanceTestCase.Intermediates mIntermediates;
+    private String mExpecting;
+
+    // Synchronization of activity result.
+    private boolean mFinished;
+    private int mResultCode = 0;
+    private Intent mData;
+    private RuntimeException mResultStack = null;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mIntent = new Intent(mContext, LaunchpadActivity.class);
+        mIntermediates = null;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mIntermediates = null;
+        super.tearDown();
+    }
+
+    public boolean isPerformanceOnly() {
+        return false;
+    }
+
+    public void setInternalIterations(int count) {
+    }
+
+    public void startTiming(boolean realTime) {
+        if (mIntermediates != null) {
+            mIntermediates.startTiming(realTime);
+        }
+    }
+
+    public void addIntermediate(String name) {
+        if (mIntermediates != null) {
+            mIntermediates.addIntermediate(name);
+        }
+    }
+
+    public void addIntermediate(String name, long timeInNS) {
+        if (mIntermediates != null) {
+            mIntermediates.addIntermediate(name, timeInNS);
+        }
+    }
+
+    public void finishTiming(boolean realTime) {
+        if (mIntermediates != null) {
+            mIntermediates.finishTiming(realTime);
+        }
+    }
+
+    public void activityFinished(int resultCode, Intent data, RuntimeException where) {
+        finishWithResult(resultCode, data, where);
+    }
+
+    public Intent editIntent() {
+        return mIntent;
+    }
+
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    public int startPerformance(Intermediates intermediates) {
+        mIntermediates = intermediates;
+        return 1;
+    }
+
+    public void finishGood() {
+        finishWithResult(Activity.RESULT_OK, null);
+    }
+
+    public void finishBad(String error) {
+        finishWithResult(Activity.RESULT_CANCELED, new Intent().setAction(error));
+    }
+
+    public void finishWithResult(int resultCode, Intent data) {
+        final RuntimeException where = new RuntimeException("Original error was here");
+        where.fillInStackTrace();
+        finishWithResult(resultCode, data, where);
+    }
+
+    public void finishWithResult(int resultCode, Intent data, RuntimeException where) {
+        synchronized (this) {
+            mResultCode = resultCode;
+            mData = data;
+            mResultStack = where;
+            mFinished = true;
+            notifyAll();
+        }
+    }
+
+    public int runLaunchpad(String action) {
+        startLaunchpadActivity(action);
+        return waitForResultOrThrow(TIMEOUT_MS);
+    }
+
+    private void startLaunchpadActivity(String action) {
+        LaunchpadActivity.setCallingTest(this);
+
+        synchronized (this) {
+            mIntent.setAction(action);
+            mFinished = false;
+            mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(mIntent);
+        }
+    }
+
+    public int waitForResultOrThrow(int timeoutMs) {
+        return waitForResultOrThrow(timeoutMs, null);
+    }
+
+    public int waitForResultOrThrow(int timeoutMs, String expected) {
+        final int res = waitForResult(timeoutMs, expected);
+
+        if (res == Activity.RESULT_CANCELED) {
+            if (mResultStack != null) {
+                throw new RuntimeException(mData != null ? mData.toString() : "Unable to launch",
+                        mResultStack);
+            } else {
+                throw new RuntimeException(mData != null ? mData.toString() : "Unable to launch");
+            }
+        }
+        return res;
+    }
+
+    public int waitForResult(int timeoutMs, String expected) {
+        mExpecting = expected;
+
+        final long endTime = System.currentTimeMillis() + timeoutMs;
+
+        boolean timeout = false;
+        synchronized (this) {
+            while (!mFinished) {
+                final long delay = endTime - System.currentTimeMillis();
+                if (delay < 0) {
+                    timeout = true;
+                    break;
+                }
+
+                try {
+                    wait(delay);
+                } catch (final java.lang.InterruptedException e) {
+                    // do nothing
+                }
+            }
+        }
+
+        mFinished = false;
+
+        if (timeout) {
+            mResultCode = Activity.RESULT_CANCELED;
+            onTimeout();
+        }
+        return mResultCode;
+    }
+
+
+    public int getResultCode() {
+        return mResultCode;
+    }
+
+    public Intent getResultData() {
+        return mData;
+    }
+
+    public RuntimeException getResultStack() {
+        return mResultStack;
+    }
+
+    public void onTimeout() {
+        final String msg = mExpecting == null ? "Timeout" : "Timeout while expecting " + mExpecting;
+        finishWithResult(Activity.RESULT_CANCELED, new Intent().setAction(msg));
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/AliasActivityStub.java b/tests/app/app/src/android/app/stubs/AliasActivityStub.java
new file mode 100644
index 0000000..7d2d469
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/AliasActivityStub.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.stubs;
+
+import android.app.AliasActivity;
+import android.os.Bundle;
+
+public class AliasActivityStub extends AliasActivity {
+
+    public static boolean isOnCreateCalled = false;
+    public static boolean isFinished = false;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        isOnCreateCalled = true;
+    }
+
+    @Override
+    public void finish() {
+        super.finish();
+        isFinished = true;
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/AppStubActivity.java b/tests/app/app/src/android/app/stubs/AppStubActivity.java
new file mode 100644
index 0000000..1da2421
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/AppStubActivity.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ContextMenu.ContextMenuInfo;
+
+/**
+ * A minimal "Hello, World!" application.
+ */
+public class AppStubActivity extends Activity {
+    private Dialog mDialog;
+    public boolean mOnPrepareDialog;
+    public boolean mOnOptionsMenuClosedCalled;
+    public boolean mOnPrepareOptionsMenuCalled;
+    public boolean mOnOptionsItemSelectedCalled;
+    public boolean mOnCreateOptionsMenu;
+    public boolean mIndterminate = false;
+    public boolean mIndterminatevisibility = false;
+    public boolean mSecPro = false;
+    public boolean mOnContextItemSelectedCalled;
+    public boolean mOnCreateContextMenu;
+    public boolean mApplyResourceCalled;
+    public boolean mCreateContextMenuCalled;
+    public boolean mRequestWinFeatureRet = false;
+
+    public AppStubActivity() {
+
+    }
+
+    public void finalize() {
+        try {
+            super.finalize();
+        } catch (Throwable exception) {
+            System.err.print("exception!");
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState){
+        super.onCreate(savedInstanceState);
+        mRequestWinFeatureRet = requestWindowFeature(1);
+        setContentView(R.layout.app_activity);
+    }
+
+    public Dialog getDialogById(int id) {
+        return mDialog;
+    }
+
+    @Override
+    public Dialog onCreateDialog(int id) {
+        super.onCreateDialog(id);
+        mDialog = new Dialog(this);
+        return mDialog;
+    }
+
+    @Override
+    protected void onPrepareDialog(int id, Dialog dialog) {
+        super.onPrepareDialog(id, dialog);
+        mOnPrepareDialog = true;
+    }
+
+    @Override
+    public void onOptionsMenuClosed(Menu menu) {
+        super.onOptionsMenuClosed(menu);
+        mOnOptionsMenuClosedCalled = true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        mOnPrepareOptionsMenuCalled = true;
+        return super.onPrepareOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        mOnCreateOptionsMenu = true;
+        if(menu != null)
+            menu.add(0, 0, 0, "Fake Item");
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        mOnOptionsItemSelectedCalled = true;
+        return super.onOptionsItemSelected(item);
+    }
+
+    public boolean setProBarIndeterminate(boolean indeterminate){
+        mIndterminate = indeterminate;
+        super.setProgressBarIndeterminate(indeterminate);
+        return mIndterminate;
+    }
+
+    public boolean setProBarIndeterminateVisibility(boolean visible){
+        mIndterminatevisibility = visible;
+        super.setProgressBarIndeterminateVisibility(visible);
+        return mIndterminatevisibility;
+    }
+
+    public boolean setSecPro(int secPro){
+        mSecPro = true;
+        super.setSecondaryProgress(secPro);
+        return mSecPro;
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item){
+        mOnContextItemSelectedCalled = true;
+        return super.onContextItemSelected(item);
+    }
+
+    @Override
+    public void onApplyThemeResource( Resources.Theme theme,
+                                      int resid,
+                                      boolean first){
+        super.onApplyThemeResource(theme,resid,first);
+        mApplyResourceCalled = true;
+    }
+
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+        super.onCreateContextMenu(menu,v,menuInfo);
+        mCreateContextMenuCalled = true;
+    }
+}
+
diff --git a/tests/app/app/src/android/app/stubs/CTSActivityTestCaseBase.java b/tests/app/app/src/android/app/stubs/CTSActivityTestCaseBase.java
new file mode 100644
index 0000000..44ff6b2
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/CTSActivityTestCaseBase.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.cts.util.CTSResult;
+import android.test.InstrumentationTestCase;
+
+public class CTSActivityTestCaseBase extends InstrumentationTestCase implements CTSResult {
+
+    private Sync mSync;
+    static class Sync {
+        public boolean mHasNotify;
+        public int mResult;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mSync = new Sync();
+    }
+
+    public void setResult(int resultCode) {
+        synchronized (mSync) {
+            mSync.mHasNotify = true;
+            mSync.mResult = resultCode;
+            mSync.notify();
+        }
+    }
+
+    protected void waitForResult() throws InterruptedException {
+        synchronized (mSync) {
+            while (!mSync.mHasNotify) {
+                mSync.wait();
+            }
+            assertEquals(CTSResult.RESULT_OK, mSync.mResult);
+        }
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/ChildActivity.java b/tests/app/app/src/android/app/stubs/ChildActivity.java
new file mode 100644
index 0000000..559b101
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ChildActivity.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.stubs;
+
+import android.app.Activity;
+
+public class ChildActivity extends Activity {
+
+    public static boolean isStarted = false;
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        isStarted = true;
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/ChildTabActivity.java b/tests/app/app/src/android/app/stubs/ChildTabActivity.java
new file mode 100644
index 0000000..1f0fb37
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ChildTabActivity.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+
+/**
+ * An empty activity for the TabActivity test
+ */
+public class ChildTabActivity extends Activity {
+}
diff --git a/tests/app/app/src/android/app/stubs/ClearTop.java b/tests/app/app/src/android/app/stubs/ClearTop.java
new file mode 100644
index 0000000..94fcc57
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ClearTop.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public class ClearTop extends Activity {
+    public static final String WAIT_CLEAR_TASK = "waitClearTask";
+    private static final String TAG = "ClearTop";
+    public ClearTop() {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        final Intent intent = new Intent(getIntent()).setAction(LocalScreen.CLEAR_TASK).setClass(
+                this, LocalScreen.class);
+        startActivity(intent);
+    }
+
+    @Override
+    public void onNewIntent(Intent intent) {
+        Log.i(TAG, "onNewIntent");
+        if (LocalScreen.CLEAR_TASK.equals(intent.getAction())) {
+            setResult(RESULT_OK);
+        } else {
+            setResult(RESULT_CANCELED, new Intent().setAction("New intent received " + intent
+                    + ", expecting action " + TestedScreen.CLEAR_TASK));
+        }
+        finish();
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/DialogStubActivity.java b/tests/app/app/src/android/app/stubs/DialogStubActivity.java
new file mode 100644
index 0000000..d77b9a3
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/DialogStubActivity.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.DatePickerDialog;
+import android.app.Dialog;
+import android.app.TimePickerDialog;
+import android.app.DatePickerDialog.OnDateSetListener;
+import android.app.TimePickerDialog.OnTimeSetListener;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.DialogInterface.OnCancelListener;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.DatePicker;
+import android.widget.TimePicker;
+
+/*
+ * Stub class for  Dialog, AlertDialog, DatePickerDialog, TimePickerDialog etc.
+ */
+public class DialogStubActivity extends Activity {
+    public static final int TEST_DIALOG_WITHOUT_THEME = 0;
+    public static final int TEST_DIALOG_WITH_THEME = 1;
+    public static final int TEST_ALERTDIALOG = 2;
+    public static final int TEST_CUSTOM_ALERTDIALOG = 3;
+    public static final int TEST_DATEPICKERDIALOG = 4;
+    public static final int TEST_DATEPICKERDIALOG_WITH_THEME = 5;
+    public static final int TEST_TIMEPICKERDIALOG = 6;
+    public static final int TEST_TIMEPICKERDIALOG_WITH_THEME = 7;
+    public static final int TEST_ONSTART_AND_ONSTOP = 8;
+    public static final int TEST_ALERTDIALOG_DEPRECATED = 9;
+    public static final int TEST_ALERTDIALOG_CALLBACK = 10;
+    public static final int TEST_CUSTOM_ALERTDIALOG_VIEW = 11;
+    public static final int TEST_ALERTDIALOG_DEPRECATED_WITH_MESSAGE = 12;
+    public static final int TEST_ALERTDIALOG_THEME = 13;
+    public static final int TEST_ALERTDIALOG_CANCELABLE = 14;
+    public static final int TEST_ALERTDIALOG_NOT_CANCELABLE = 15;
+    public static final int TEST_PROTECTED_CANCELABLE = 16;
+    public static final int TEST_PROTECTED_NOT_CANCELABLE = 17;
+
+    public static final int SPACING_LEFT = 10;
+    public static final int SPACING_TOP = 20;
+    public static final int SPACING_RIGHT = 30;
+    public static final int SPACING_BOTTOM = 40;
+    public static int buttonIndex;
+
+    public static final String DEFAULT_ALERTDIALOG_TITLE = "AlertDialog";
+    public static final String DEFAULT_ALERTDIALOG_MESSAGE = "AlertDialog message";
+    private static final String LOG_TAG = "DialogStubActivity";
+
+    public boolean isPositiveButtonClicked = false;
+    public boolean isNegativeButtonClicked = false;
+    public boolean isNeutralButtonClicked = false;
+    public boolean isCallBackCalled;
+    public boolean onCancelCalled;
+    public boolean onKeyDownCalled;
+    public boolean onKeyUpCalled;
+    public boolean onCreateCalled;
+    public boolean onCancelListenerCalled;
+    public boolean onClickCalled;
+    public static boolean onDateChangedCalled;
+    public static boolean onRestoreInstanceStateCalled;
+    public boolean onSaveInstanceStateCalled;
+    public int updatedYear;
+    public int updatedMonth;
+    public int updatedDay;
+
+    public final int INITIAL_YEAR = 2008;
+    public final int INITIAL_MONTH = 7;
+    public final int INITIAL_DAY_OF_MONTH = 27;
+    private final int INITIAL_HOUR = 10;
+    private final int INITIAL_MINUTE = 35;
+    private Dialog mDialog;
+    private AlertDialog mAlertDialog;
+    private OnDateSetListener mOnDateSetListener = new OnDateSetListener() {
+        public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
+            updatedYear = year;
+            updatedMonth = monthOfYear;
+            updatedDay = dayOfMonth;
+        }
+    };
+
+    @SuppressWarnings("deprecation")
+    @Override
+    protected Dialog onCreateDialog(int id) {
+        switch (id) {
+            case TEST_DIALOG_WITHOUT_THEME:
+                mDialog = new Dialog(this);
+                mDialog.setTitle("Hello, Dialog");
+                break;
+
+            case TEST_DIALOG_WITH_THEME:
+                mDialog = new Dialog(this, 1);
+                break;
+
+            case TEST_ALERTDIALOG:
+                mDialog = getAlertDialogInstance(false);
+                break;
+
+            case TEST_CUSTOM_ALERTDIALOG:
+                mDialog = getCustomAlertDialogInstance(false);
+                break;
+
+            case TEST_CUSTOM_ALERTDIALOG_VIEW:
+                mDialog = getCustomAlertDialogInstance(true);
+                break;
+
+            case TEST_DATEPICKERDIALOG:
+                mDialog = new MockDatePickerDialog(this, mOnDateSetListener, INITIAL_YEAR,
+                        INITIAL_MONTH, INITIAL_DAY_OF_MONTH);
+                break;
+
+            case TEST_DATEPICKERDIALOG_WITH_THEME:
+                mDialog = new MockDatePickerDialog(this,
+                        com.android.internal.R.style.Theme_Translucent, mOnDateSetListener,
+                        INITIAL_YEAR, INITIAL_MONTH, INITIAL_DAY_OF_MONTH);
+                break;
+
+            case TEST_TIMEPICKERDIALOG:
+                mDialog = new TimePickerDialog(this, new OnTimeSetListener() {
+                    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
+                        isCallBackCalled = true;
+                    }
+                }, INITIAL_HOUR, INITIAL_MINUTE, true);
+                break;
+
+            case TEST_TIMEPICKERDIALOG_WITH_THEME:
+                mDialog = new TimePickerDialog(this,
+                        com.android.internal.R.style.Theme_Translucent, null, INITIAL_HOUR,
+                        INITIAL_MINUTE, true);
+                break;
+
+            case TEST_ONSTART_AND_ONSTOP:
+                mDialog = new TestDialog(this);
+                Log.i(LOG_TAG, "mTestDialog:" + mDialog);
+                return mDialog;
+
+            case TEST_ALERTDIALOG_DEPRECATED:
+                mDialog = getAlertDialogInstance(true);
+                break;
+
+            case TEST_ALERTDIALOG_DEPRECATED_WITH_MESSAGE:
+                final Handler handler = new Handler() {
+                    @Override
+                    public void handleMessage(Message msg) {
+                        buttonIndex = msg.what;
+                        super.handleMessage(msg);
+                    }
+                };
+                final Message positiveMessage = Message.obtain();
+                positiveMessage.setTarget(handler);
+                positiveMessage.what = DialogInterface.BUTTON_POSITIVE;
+
+                final Message negativeMessage = Message.obtain();
+                negativeMessage.setTarget(handler);
+                negativeMessage.what = DialogInterface.BUTTON_NEGATIVE;
+
+                final Message neutralMessage = Message.obtain();
+                neutralMessage.setTarget(handler);
+                neutralMessage.what = DialogInterface.BUTTON_NEUTRAL;
+                mAlertDialog = getAlertDialogInstance(false);
+                mAlertDialog.setButton(getString(R.string.alert_dialog_positive), positiveMessage);
+                mAlertDialog.setButton2(getString(R.string.alert_dialog_negative), negativeMessage);
+                mAlertDialog.setButton3(getString(R.string.alert_dialog_neutral), neutralMessage);
+                mDialog = mAlertDialog;
+                break;
+
+            case TEST_ALERTDIALOG_CALLBACK:
+                mDialog = new MockAlertDialog(this);
+                break;
+            case TEST_ALERTDIALOG_THEME:
+                mDialog = new MockAlertDialog(this, R.style.Theme_AlertDialog);
+                break;
+            case TEST_ALERTDIALOG_CANCELABLE:
+                mDialog = getAlertDialogCancelablInstance(true);
+                break;
+            case TEST_ALERTDIALOG_NOT_CANCELABLE:
+                mDialog = getAlertDialogCancelablInstance(false);
+                break;
+            case TEST_PROTECTED_CANCELABLE:
+                mDialog = new TestDialog(this, true, new OnCancelListener() {
+                    public void onCancel(DialogInterface dialog) {
+                        onCancelListenerCalled = true;
+                    }
+                });
+                break;
+            case TEST_PROTECTED_NOT_CANCELABLE:
+                mDialog = new TestDialog(this, false, new OnCancelListener() {
+                    public void onCancel(DialogInterface dialog) {
+                        onCancelListenerCalled = true;
+                    }
+                });
+                break;
+            default:
+                break;
+        }
+
+        Log.i(LOG_TAG, "mDialog:" + mDialog);
+        return mDialog;
+    }
+
+    private AlertDialog getAlertDialogCancelablInstance(boolean cancelable) {
+        OnCancelListener cancelListener = new OnCancelListener() {
+            public void onCancel(DialogInterface dialog) {
+                onCancelCalled = true;
+            }
+        };
+        return new MockAlertDialog(this, cancelable, cancelListener);
+    }
+
+    @SuppressWarnings("deprecation")
+    private AlertDialog getAlertDialogInstance(boolean deprecated) {
+        mAlertDialog = new AlertDialog.Builder(DialogStubActivity.this).create();
+        mAlertDialog.setIcon(R.drawable.pass);
+        mAlertDialog.setTitle(DEFAULT_ALERTDIALOG_TITLE);
+        mAlertDialog.setMessage(DEFAULT_ALERTDIALOG_MESSAGE);
+        mAlertDialog.setInverseBackgroundForced(true);
+        final DialogInterface.OnClickListener positiveListener = new MockOnClickListener(
+                DialogInterface.BUTTON_POSITIVE);
+        final DialogInterface.OnClickListener netativeListener = new MockOnClickListener(
+                DialogInterface.BUTTON_NEGATIVE);
+        final DialogInterface.OnClickListener neutralListener = new MockOnClickListener(
+                DialogInterface.BUTTON_NEUTRAL);
+
+        if (deprecated) {
+            mAlertDialog.setButton(getString(R.string.alert_dialog_positive), positiveListener);
+            mAlertDialog.setButton2(getString(R.string.alert_dialog_negative), netativeListener);
+            mAlertDialog.setButton3(getString(R.string.alert_dialog_neutral), neutralListener);
+        } else {
+            mAlertDialog.setButton(DialogInterface.BUTTON_POSITIVE,
+                    getString(R.string.alert_dialog_positive), positiveListener);
+            mAlertDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
+                    getString(R.string.alert_dialog_negative), netativeListener);
+            mAlertDialog.setButton(DialogInterface.BUTTON_NEUTRAL,
+                    getString(R.string.alert_dialog_neutral), neutralListener);
+        }
+        return mAlertDialog;
+
+    }
+
+    private AlertDialog getCustomAlertDialogInstance(boolean withSpacing) {
+        final LayoutInflater inflate = getLayoutInflater();
+        final View customTitleViewCustom = inflate.inflate(R.layout.alertdialog_custom_title, null);
+        final View textEntryView = inflate.inflate(R.layout.alert_dialog_text_entry_2, null);
+        mAlertDialog = new AlertDialog.Builder(DialogStubActivity.this).create();
+        mAlertDialog.setCustomTitle(customTitleViewCustom);
+        mAlertDialog.setMessage(DEFAULT_ALERTDIALOG_MESSAGE);
+        if (withSpacing) {
+            mAlertDialog.setView(textEntryView, SPACING_LEFT, SPACING_TOP, SPACING_RIGHT,
+                    SPACING_BOTTOM);
+        } else {
+            mAlertDialog.setView(textEntryView);
+        }
+
+        return mAlertDialog;
+
+    }
+
+    public Dialog getDialog() {
+        return mDialog;
+    }
+
+    public String getDialogTitle() {
+        return (String) mDialog.getWindow().getAttributes().getTitle();
+    }
+
+    private static final String TEST_DIALOG_NUMBER_EXTRA = "testDialogNumber";
+
+    public static <T extends Activity> T startDialogActivity(
+            ActivityInstrumentationTestCase2<T> testCase, int dialogNumber) {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.putExtra(TEST_DIALOG_NUMBER_EXTRA, dialogNumber);
+        testCase.setActivityIntent(intent);
+        return testCase.getActivity();
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.dialog_stub_layout);
+
+        Intent intent = getIntent();
+        int dialogNum = intent.getIntExtra(TEST_DIALOG_NUMBER_EXTRA, -1);
+        if (dialogNum != -1) {
+            showDialog(dialogNum);
+        }
+    }
+
+    public void setUpTitle(final String title) {
+        runOnUiThread(new Runnable() {
+            public void run() {
+                getDialog().setTitle(title);
+            }
+        });
+    }
+
+    public void setUpTitle(final int id) {
+        runOnUiThread(new Runnable() {
+            public void run() {
+                getDialog().setTitle(id);
+            }
+        });
+    }
+
+    class MockAlertDialog extends AlertDialog {
+        public MockAlertDialog(Context context) {
+            super(context);
+        }
+
+        public MockAlertDialog(Context context, int theme) {
+            super(context, theme);
+        }
+
+        public MockAlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
+            super(context, cancelable, cancelListener);
+        }
+
+        @Override
+        public boolean onKeyDown(int keyCode, KeyEvent event) {
+            onKeyDownCalled = true;
+            return super.onKeyDown(keyCode, event);
+        }
+
+        @Override
+        public boolean onKeyUp(int keyCode, KeyEvent event) {
+            onKeyUpCalled = true;
+            return super.onKeyUp(keyCode, event);
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            onCreateCalled = true;
+            super.onCreate(savedInstanceState);
+        }
+
+    }
+
+    class MockOnClickListener implements DialogInterface.OnClickListener {
+        private final int mId;
+
+        public MockOnClickListener(final int buttonId) {
+            mId = buttonId;
+        }
+
+        public void onClick(DialogInterface dialog, int which) {
+            switch (mId) {
+                case DialogInterface.BUTTON_POSITIVE:
+                    isPositiveButtonClicked = true;
+                    break;
+                case DialogInterface.BUTTON_NEGATIVE:
+                    isNegativeButtonClicked = true;
+                    break;
+                case DialogInterface.BUTTON_NEUTRAL:
+                    isNeutralButtonClicked = true;
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    class MockDatePickerDialog extends DatePickerDialog {
+        public MockDatePickerDialog(Context context, OnDateSetListener callBack, int year,
+                int monthOfYear, int dayOfMonth) {
+            super(context, callBack, year, monthOfYear, dayOfMonth);
+        }
+
+        public MockDatePickerDialog(Context context, int theme, OnDateSetListener callBack,
+                int year, int monthOfYear, int dayOfMonth) {
+            super(context, theme, callBack, year, monthOfYear, dayOfMonth);
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            onClickCalled = true;
+            super.onClick(dialog, which);
+        }
+
+        @Override
+        public void onDateChanged(DatePicker view, int year, int month, int day) {
+            onDateChangedCalled = true;
+            super.onDateChanged(view, year, month, day);
+        }
+
+        @Override
+        public void onRestoreInstanceState(Bundle savedInstanceState) {
+            onRestoreInstanceStateCalled = true;
+            super.onRestoreInstanceState(savedInstanceState);
+        }
+
+        @Override
+        public Bundle onSaveInstanceState() {
+            onSaveInstanceStateCalled = true;
+            return super.onSaveInstanceState();
+        }
+
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/ExpandableListTestActivity.java b/tests/app/app/src/android/app/stubs/ExpandableListTestActivity.java
new file mode 100644
index 0000000..ab377d9
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ExpandableListTestActivity.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.stubs;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import android.app.ExpandableListActivity;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.view.ContextMenu;
+import android.view.View;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.ExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.SimpleExpandableListAdapter;
+
+import com.android.internal.R;
+import com.android.internal.view.menu.ContextMenuBuilder;
+import com.google.android.collect.Lists;
+
+public class ExpandableListTestActivity extends ExpandableListActivity {
+    private static final String NAME = "NAME";
+    private static final String IS_EVEN = "IS_EVEN";
+    private boolean mOnContentChangedCalled = false;
+    private boolean mOnCreateContextMenuCalled = false;
+    private boolean mOnGroupCollapseCalled = false;
+    private boolean mOnGroupExpandCalled = false;
+    private ExpandableListAdapter mAdapter;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final List<Map<String, String>> groupData = Lists.newArrayList();
+        final List<List<Map<String, String>>> childData = Lists.newArrayList();
+        for (int i = 0; i < 20; i++) {
+            final Map<String, String> curGroupMap = new HashMap<String, String>();
+            groupData.add(curGroupMap);
+            curGroupMap.put(NAME, "Group " + i);
+            curGroupMap.put(IS_EVEN, (i % 2 == 0) ? "This group is even" : "This group is odd");
+
+            final List<Map<String, String>> children = Lists.newArrayList();
+            for (int j = 0; j < 15; j++) {
+                Map<String, String> curChildMap = new HashMap<String, String>();
+                children.add(curChildMap);
+                curChildMap.put(NAME, "Child " + j);
+                curChildMap.put(IS_EVEN, (j % 2 == 0) ? "This child is even" : "This child is odd");
+            }
+            childData.add(children);
+        }
+
+        // Set up our adapter
+        mAdapter = new SimpleExpandableListAdapter(this, groupData,
+                R.layout.simple_expandable_list_item_1,
+                new String[] { NAME, IS_EVEN }, new int[] { R.id.text1, R.id.text2 }, childData,
+                R.layout.simple_expandable_list_item_2,
+                new String[] { NAME, IS_EVEN }, new int[] { R.id.text1, R.id.text2 });
+        setListAdapter(mAdapter);
+
+    }
+
+    private int testCallback() {
+        final ExpandableListView v = getExpandableListView();
+        final ExpandableListAdapter a = getExpandableListAdapter();
+        final View convertView = new View(this);
+        final View gv = a.getGroupView(0, true, convertView, v);
+        v.setOnCreateContextMenuListener(this);
+        v.createContextMenu(new ContextMenuBuilder(this));
+        for (int i = 0; i < 20; i++) {
+            v.expandGroup(i);
+            v.performClick();
+            v.performLongClick();
+            for (int k = 0; k < 15; k++) {
+                v.performItemClick(gv, i, k);
+            }
+            v.collapseGroup(i);
+        }
+        if (mOnContentChangedCalled && mOnCreateContextMenuCalled
+                && mOnGroupCollapseCalled && mOnGroupExpandCalled)
+            return RESULT_OK;
+
+        return RESULT_CANCELED;
+    }
+
+    private int testView() {
+        final ExpandableListView currentView = getExpandableListView();
+        for (int i = 0; i < 20; i++) {
+            if (!currentView.expandGroup(i))
+                return RESULT_CANCELED;
+            if (!currentView.collapseGroup(i))
+                return RESULT_CANCELED;
+        }
+        final View otherView = findViewById(android.R.id.list);
+        setContentView(otherView);
+        if (!otherView.equals(getExpandableListView()))
+            return RESULT_CANCELED;
+        setContentView(currentView);
+        return RESULT_OK;
+    }
+
+    private int testSelecte() {
+        final ExpandableListView v = getExpandableListView();
+        for (int i = 0; i < 20; i++) {
+            v.expandGroup(i);
+            setSelectedGroup(i);
+            for (int k = 0; k < 15; k++) {
+                setSelectedChild(i, k, false);
+                if (ExpandableListView.getPackedPositionForChild(i, k) != getSelectedPosition())
+                    return RESULT_CANCELED;
+            }
+
+            for (int k = 0; k < 15; k++) {
+                setSelectedChild(i, k, true);
+                if (ExpandableListView.getPackedPositionForChild(i, k) != getSelectedPosition())
+                    return RESULT_CANCELED;
+            }
+            v.collapseGroup(i);
+        }
+        return RESULT_OK;
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        final String action = getIntent().getAction();
+        if (LaunchpadActivity.EXPANDLIST_SELECT.equals(action)) {
+            setResult(testSelecte());
+        } else if (LaunchpadActivity.EXPANDLIST_VIEW.equals(action)) {
+            setResult(testView());
+        } else if (LaunchpadActivity.EXPANDLIST_CALLBACK.equals(action)) {
+            setResult(testCallback());
+        }
+        Looper.myQueue().addIdleHandler(new Idler());
+    }
+
+    protected void onRestoreInstanceState(Bundle state) {
+        super.onRestoreInstanceState(state);
+    }
+
+    @Override
+    public void onContentChanged() {
+        mOnContentChangedCalled = true;
+        super.onContentChanged();
+    }
+
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View v,
+            ContextMenuInfo menuInfo) {
+        mOnCreateContextMenuCalled = true;
+        super.onCreateContextMenu(menu, v, menuInfo);
+    }
+
+    @Override
+    public void onGroupCollapse(int groupPosition) {
+        mOnGroupCollapseCalled = true;
+        super.onGroupCollapse(groupPosition);
+    }
+
+    @Override
+    public void onGroupExpand(int groupPosition) {
+        mOnGroupExpandCalled = true;
+        super.onGroupExpand(groupPosition);
+    }
+
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+    }
+
+    protected void onStop() {
+        super.onStop();
+    }
+
+    private class Idler implements MessageQueue.IdleHandler {
+        public final boolean queueIdle() {
+            finish();
+            return false;
+        }
+    }
+
+}
diff --git a/tests/app/app/src/android/app/stubs/FragmentTestActivity.java b/tests/app/app/src/android/app/stubs/FragmentTestActivity.java
new file mode 100644
index 0000000..65ba911
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/FragmentTestActivity.java
@@ -0,0 +1,192 @@
+/*
+ * 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.app.stubs;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.transition.Transition;
+import android.transition.Transition.TransitionListener;
+import android.transition.TransitionInflater;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A simple activity used for Fragment Transitions
+ */
+public class FragmentTestActivity extends Activity {
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.activity_content);
+    }
+
+    public static class TestFragment extends Fragment {
+        public static final int ENTER = 0;
+        public static final int RETURN = 1;
+        public static final int EXIT = 2;
+        public static final int REENTER = 3;
+        public static final int SHARED_ELEMENT_ENTER = 4;
+        public static final int SHARED_ELEMENT_RETURN = 5;
+        private static final int TRANSITION_COUNT = 6;
+
+        private static final String LAYOUT_ID = "layoutId";
+        private static final String TRANSITION_KEY = "transition_";
+        private int mLayoutId = R.layout.fragment_start;
+        private final int[] mTransitionIds = new int[] {
+                android.R.transition.explode,
+                android.R.transition.explode,
+                android.R.transition.fade,
+                android.R.transition.fade,
+                android.R.transition.move,
+                android.R.transition.move,
+        };
+        private final TransitionCalledListener[] mListeners =
+                new TransitionCalledListener[TRANSITION_COUNT];
+        private OnTransitionListener mOnTransitionListener;
+
+        public TestFragment() {
+            for (int i = 0; i < TRANSITION_COUNT; i++) {
+                mListeners[i] = new TransitionCalledListener();
+            }
+        }
+
+        public TestFragment(int layoutId) {
+            this();
+            mLayoutId = layoutId;
+        }
+
+        public void clearTransitions() {
+            for (int i = 0; i < TRANSITION_COUNT; i++) {
+                mTransitionIds[i] = 0;
+            }
+        }
+
+        public void clearNotifications() {
+            for (int i = 0; i < TRANSITION_COUNT; i++) {
+                mListeners[i].transitionStarted = false;
+                mListeners[i].transitionEnded = false;
+            }
+        }
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            if (savedInstanceState != null) {
+                mLayoutId = savedInstanceState.getInt(LAYOUT_ID, mLayoutId);
+                for (int i = 0; i < TRANSITION_COUNT; i++) {
+                    String key = TRANSITION_KEY + i;
+                    mTransitionIds[i] = savedInstanceState.getInt(key, mTransitionIds[i]);
+                }
+            }
+        }
+
+        @Override
+        public void onSaveInstanceState(Bundle outState) {
+            super.onSaveInstanceState(outState);
+            outState.putInt(LAYOUT_ID, mLayoutId);
+            for (int i = 0; i < TRANSITION_COUNT; i++) {
+                String key = TRANSITION_KEY + i;
+                outState.putInt(key, mTransitionIds[i]);
+            }
+        }
+
+        @Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            return inflater.inflate(mLayoutId, container, false);
+        }
+
+        @Override
+        public void onAttach(Context context) {
+            super.onAttach(context);
+            setEnterTransition(loadTransition(ENTER));
+            setReenterTransition(loadTransition(REENTER));
+            setExitTransition(loadTransition(EXIT));
+            setReturnTransition(loadTransition(RETURN));
+            setSharedElementEnterTransition(loadTransition(SHARED_ELEMENT_ENTER));
+            setSharedElementReturnTransition(loadTransition(SHARED_ELEMENT_RETURN));
+        }
+
+        public void setOnTransitionListener(OnTransitionListener listener) {
+            mOnTransitionListener = listener;
+        }
+
+        public boolean wasStartCalled(int transitionKey) {
+            return mListeners[transitionKey].transitionStarted;
+        }
+
+        public boolean wasEndCalled(int transitionKey) {
+            return mListeners[transitionKey].transitionEnded;
+        }
+
+        private Transition loadTransition(int key) {
+            final int id = mTransitionIds[key];
+            if (id == 0) {
+                return null;
+            }
+            Transition transition = TransitionInflater.from(getActivity()).inflateTransition(id);
+            transition.addListener(mListeners[key]);
+            return transition;
+        }
+
+        private void notifyTransition() {
+            if (mOnTransitionListener != null) {
+                mOnTransitionListener.onTransition(this);
+            }
+        }
+
+        private class TransitionCalledListener implements TransitionListener {
+            public boolean transitionStarted;
+            public boolean transitionEnded;
+
+            public TransitionCalledListener() {
+            }
+
+            @Override
+            public void onTransitionStart(Transition transition) {
+                transitionStarted = true;
+                notifyTransition();
+            }
+
+            @Override
+            public void onTransitionEnd(Transition transition) {
+                transitionEnded = true;
+                notifyTransition();
+            }
+
+            @Override
+            public void onTransitionCancel(Transition transition) {
+            }
+
+            @Override
+            public void onTransitionPause(Transition transition) {
+            }
+
+            @Override
+            public void onTransitionResume(Transition transition) {
+            }
+        }
+    }
+
+    public interface OnTransitionListener {
+        void onTransition(TestFragment fragment);
+    }
+
+}
diff --git a/tests/app/app/src/android/app/stubs/ISecondary.aidl b/tests/app/app/src/android/app/stubs/ISecondary.aidl
new file mode 100644
index 0000000..2f3ec25
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/ISecondary.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+interface ISecondary {
+
+    int getPid();
+
+    long getElapsedCpuTime();
+
+    String getTimeZoneID();
+}
diff --git a/tests/app/app/src/android/app/stubs/InstrumentationTestActivity.java b/tests/app/app/src/android/app/stubs/InstrumentationTestActivity.java
new file mode 100644
index 0000000..8e36beb
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/InstrumentationTestActivity.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import java.util.ArrayList;
+import java.util.List;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.TextView;
+
+public class InstrumentationTestActivity extends Activity {
+
+    private boolean mOnCreateCalled;
+    private boolean mOnDestroyCalled ;
+    private boolean mOnNewIntentCalled;
+    private boolean mOnPauseCalled;
+    private boolean mOnPostCreate;
+    private boolean mOnRestart;
+    private boolean mOnRestoreInstanceState;
+    private boolean mOnResume;
+    private boolean mOnSaveInstanceState;
+    private boolean mOnStart;
+    private boolean mOnStop;
+    private boolean mOnMenuOpened;
+    private boolean mOnLeave;
+    private int mMenuID;
+    private boolean mOnTouchEventCalled;
+    private int mKeyDownCode;
+    private int mKeyUpCode;
+    private MotionEvent mMotionEvent;
+    private Bundle mBundle;
+    private MockTextView mTextView;
+    private List<KeyEvent> mKeyDownList = new ArrayList<KeyEvent>();
+    private List<KeyEvent> mKeyUpList = new ArrayList<KeyEvent>();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mTextView = new MockTextView(this);
+        setContentView(mTextView);
+        mOnCreateCalled = true;
+    }
+
+    class MockTextView extends TextView {
+
+        public MockTextView(Context context) {
+            super(context);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            return super.onTouchEvent(event);
+        }
+
+        @Override
+        public boolean onTrackballEvent(MotionEvent event) {
+            return super.onTrackballEvent(event);
+        }
+
+        @Override
+        public void getLocationOnScreen(int[] location) {
+            super.getLocationOnScreen(location);
+            location[0] = location[1] = 10;
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mOnDestroyCalled = true;
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        mOnNewIntentCalled = true;
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mOnPauseCalled = true;
+    }
+
+    @Override
+    protected void onPostCreate(Bundle savedInstanceState) {
+        super.onPostCreate(savedInstanceState);
+        mOnPostCreate = true;
+    }
+
+    @Override
+    protected void onRestart() {
+        super.onRestart();
+        mOnRestart = true;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+        mOnRestoreInstanceState = true;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        mOnTouchEventCalled = true;
+        mMotionEvent = event;
+        return super.onTouchEvent(event);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mOnResume = true;
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        mOnSaveInstanceState = true;
+        mBundle = outState;
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        mOnStart = true;
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        mOnStop = true;
+    }
+
+    @Override
+    protected void onUserLeaveHint() {
+        super.onUserLeaveHint();
+        mOnLeave = true;
+    }
+
+    @Override
+    public boolean onMenuOpened(int featureId, Menu menu) {
+        mOnMenuOpened = true;
+        return super.onMenuOpened(featureId, menu);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.browser, menu);
+
+        menu.add("title");
+        mOnMenuOpened = true;
+        return true;
+    }
+
+    @Override
+    public boolean onCreatePanelMenu(int featureId, Menu menu) {
+        return super.onCreatePanelMenu(featureId, menu);
+    }
+
+    @Override
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+        mMenuID = item.getItemId();
+        return super.onMenuItemSelected(featureId, item);
+    }
+
+    @Override
+    public void openContextMenu(View view) {
+        super.openContextMenu(view);
+    }
+
+    @Override
+    public void openOptionsMenu() {
+        super.openOptionsMenu();
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        mKeyDownList.add(event);
+        mKeyDownCode = keyCode;
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onTrackballEvent(MotionEvent event) {
+        mMotionEvent = event;
+        return super.onTrackballEvent(event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        mKeyUpList.add(event);
+        mKeyUpCode = keyCode;
+        return super.onKeyUp(keyCode, event);
+    }
+
+    public boolean isOnCreateCalled() {
+        return mOnCreateCalled;
+    }
+
+    public void setOnCreateCalled(boolean onCreateCalled) {
+        mOnCreateCalled = onCreateCalled;
+    }
+
+    public boolean isOnDestroyCalled() {
+        return mOnDestroyCalled;
+    }
+
+    public void setOnDestroyCalled(boolean onDestroyCalled) {
+        mOnDestroyCalled = onDestroyCalled;
+    }
+
+    public boolean isOnNewIntentCalled() {
+        return mOnNewIntentCalled;
+    }
+
+    public void setOnNewIntentCalled(boolean onNewIntentCalled) {
+        mOnNewIntentCalled = onNewIntentCalled;
+    }
+
+    public boolean isOnPauseCalled() {
+        return mOnPauseCalled;
+    }
+
+    public void setOnPauseCalled(boolean onPauseCalled) {
+        mOnPauseCalled = onPauseCalled;
+    }
+
+    public boolean isOnPostCreate() {
+        return mOnPostCreate;
+    }
+
+    public void setOnPostCreate(boolean onPostCreate) {
+        mOnPostCreate = onPostCreate;
+    }
+
+    public boolean isOnRestart() {
+        return mOnRestart;
+    }
+
+    public void setOnRestart(boolean onRestart) {
+        mOnRestart = onRestart;
+    }
+
+    public boolean isOnRestoreInstanceState() {
+        return mOnRestoreInstanceState;
+    }
+
+    public void setOnRestoreInstanceState(boolean onRestoreInstanceState) {
+        mOnRestoreInstanceState = onRestoreInstanceState;
+    }
+
+    public boolean isOnResume() {
+        return mOnResume;
+    }
+
+    public void setOnResume(boolean onResume) {
+        mOnResume = onResume;
+    }
+
+    public boolean isOnSaveInstanceState() {
+        return mOnSaveInstanceState;
+    }
+
+    public void setOnSaveInstanceState(boolean onSaveInstanceState) {
+        mOnSaveInstanceState = onSaveInstanceState;
+    }
+
+    public boolean isOnStart() {
+        return mOnStart;
+    }
+
+    public void setOnStart(boolean onStart) {
+        mOnStart = onStart;
+    }
+
+    public boolean isOnStop() {
+        return mOnStop;
+    }
+
+    public boolean isOnLeave() {
+        return mOnLeave;
+    }
+
+    public void setOnStop(boolean onStop) {
+        mOnStop = onStop;
+    }
+
+    public boolean isMOnMenuOpened() {
+        return mOnMenuOpened;
+    }
+
+    public void setOnMenuOpened(boolean onMenuOpened) {
+        mOnMenuOpened = onMenuOpened;
+    }
+
+    public int getMenuID() {
+        return mMenuID;
+    }
+
+    public void setMenuID(int menuID) {
+        mMenuID = menuID;
+    }
+
+    public MotionEvent getMotionEvent() {
+        return mMotionEvent;
+    }
+
+    public Bundle getBundle() {
+        return mBundle;
+    }
+
+    public boolean isOnTouchEventCalled() {
+        return mOnTouchEventCalled;
+    }
+
+    public void setOnTouchEventCalled(boolean onTouchEventCalled) {
+        mOnTouchEventCalled = onTouchEventCalled;
+    }
+
+    public int getKeyUpCode() {
+        return mKeyUpCode;
+    }
+
+    public int getKeyDownCode() {
+        return mKeyDownCode;
+    }
+
+    public List<KeyEvent> getKeyUpList() {
+        return mKeyUpList;
+    }
+
+    public List<KeyEvent> getKeyDownList() {
+        return mKeyDownList;
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/IntentServiceStub.java b/tests/app/app/src/android/app/stubs/IntentServiceStub.java
new file mode 100644
index 0000000..626e464
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/IntentServiceStub.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.cts.util.PollingCheck;
+import android.os.Binder;
+import android.os.IBinder;
+
+public class IntentServiceStub extends IntentService {
+    public IntentServiceStub() {
+        super("IntentServiceStub");
+    }
+
+    public static final String ISS_ADD = "add";
+    public static final String ISS_VALUE = "value";
+
+    private static int onHandleIntentCalled;
+    private static boolean onBindCalled;
+    private static boolean onCreateCalled;
+    private static boolean onDestroyCalled;
+    private static boolean onStartCalled;
+    private static int accumulator;
+
+    private static Throwable throwable;
+
+    public synchronized static void reset() {
+        onHandleIntentCalled = 0;
+        onBindCalled = false;
+        onCreateCalled = false;
+        onDestroyCalled = false;
+        onStartCalled = false;
+        accumulator = 0;
+        throwable = null;
+    }
+
+    public static void waitToFinish(long timeout) throws Throwable {
+        new PollingCheck(timeout) {
+            @Override
+            protected boolean check() {
+                synchronized (IntentServiceStub.class) {
+                    return IntentServiceStub.onDestroyCalled;
+                }
+            }
+        }.run();
+        if (throwable != null) {
+            throw throwable;
+        }
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        synchronized (IntentServiceStub.class) {
+            onHandleIntentCalled += 1;
+            try {
+                String action = intent.getAction();
+                if (action != null && action.equals(ISS_ADD)) {
+                    accumulator += intent.getIntExtra(ISS_VALUE, 0);
+                }
+            } catch (Throwable t) {
+                throwable = t;
+            }
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        synchronized (IntentServiceStub.class) {
+            onBindCalled = true;
+        }
+        return new Binder();
+    }
+
+    @Override
+    public void onCreate() {
+        synchronized (IntentServiceStub.class) {
+            onCreateCalled = true;
+        }
+        super.onCreate();
+    }
+
+    @Override
+    public void onDestroy() {
+        synchronized (IntentServiceStub.class) {
+            onDestroyCalled = true;
+        }
+        super.onDestroy();
+    }
+
+    @Override
+    public void onStart(Intent intent, int startId) {
+        synchronized (IntentService.class) {
+            onStartCalled = true;
+        }
+        super.onStart(intent, startId);
+    }
+
+    public synchronized static int getOnHandleIntentCalledCount() {
+        return onHandleIntentCalled;
+    }
+
+    public synchronized static boolean isOnBindCalled() {
+        return onBindCalled;
+    }
+
+    public synchronized static boolean isOnCreateCalled() {
+        return onCreateCalled;
+    }
+
+    public synchronized static boolean isOnDestroyCalled() {
+        return onDestroyCalled;
+    }
+
+    public synchronized static boolean isOnStartCalled() {
+        return onStartCalled;
+    }
+
+    public synchronized static int getAccumulator() {
+        return accumulator;
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/KeyguardManagerActivity.java b/tests/app/app/src/android/app/stubs/KeyguardManagerActivity.java
new file mode 100644
index 0000000..e85938d
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/KeyguardManagerActivity.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.stubs;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+
+public class KeyguardManagerActivity extends Activity {
+    private static final String TAG = "KeyguardManagerActivity";
+    public static final boolean DEBUG = false;
+    private KeyguardManager mKeyguardManager;
+    private KeyguardManager.KeyguardLock mKeyLock;
+    public int keyCode;
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
+        mKeyLock = null;
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (DEBUG) {
+            Log.d(TAG, "onResume");
+        }
+        if (mKeyLock == null) {
+            mKeyLock = mKeyguardManager.newKeyguardLock(TAG);
+            mKeyLock.disableKeyguard();
+            if (DEBUG) {
+                Log.d(TAG, "disableKeyguard");
+            }
+        }
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        this.keyCode = keyCode;
+        if (keyCode == KeyEvent.KEYCODE_0 && mKeyLock != null) {
+            mKeyLock.reenableKeyguard();
+            mKeyLock = null;
+            if (DEBUG) {
+                Log.d(TAG, "reenableKeyguard");
+            }
+        }
+        if (DEBUG) {
+            Log.d(TAG, "onKeyDown");
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/LauncherActivityStub.java b/tests/app/app/src/android/app/stubs/LauncherActivityStub.java
new file mode 100644
index 0000000..f309b04
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LauncherActivityStub.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.LauncherActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ListView;
+
+public class LauncherActivityStub extends LauncherActivity {
+    public boolean isOnCreateCalled = false;
+    public boolean isOnListItemClick = false;
+    // For testing LauncherActivity#getTargetIntent()
+    private Intent mSuperIntent;
+
+    public Intent getSuperIntent() {
+        return mSuperIntent;
+    }
+
+    @Override
+    protected Intent getTargetIntent() {
+        mSuperIntent = super.getTargetIntent();
+        Intent targetIntent = new Intent(Intent.ACTION_MAIN, null);
+        targetIntent.addCategory(Intent.CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST);
+        targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return targetIntent;
+    }
+
+    @Override
+    public Intent intentForPosition(int position) {
+        return super.intentForPosition(position);
+    }
+
+    public LauncherActivityStub() {
+        super();
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        isOnCreateCalled = true;
+    }
+
+    @Override
+    public void onListItemClick(ListView l, View v, int position, long id) {
+        super.onListItemClick(l, v, position, id);
+        isOnListItemClick = true;
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/LaunchpadActivity.java b/tests/app/app/src/android/app/stubs/LaunchpadActivity.java
new file mode 100644
index 0000000..16b1363
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LaunchpadActivity.java
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.test.PerformanceTestCase;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+class MyBadParcelable implements Parcelable {
+    public MyBadParcelable() {
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString("I am bad");
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<MyBadParcelable> CREATOR =
+        new Parcelable.Creator<MyBadParcelable>() {
+        public MyBadParcelable createFromParcel(Parcel in) {
+            return new MyBadParcelable(in);
+        }
+
+        public MyBadParcelable[] newArray(int size) {
+            return new MyBadParcelable[size];
+        }
+    };
+
+    public MyBadParcelable(Parcel in) {
+        in.readString();
+    }
+}
+
+public class LaunchpadActivity extends Activity {
+    public interface CallingTest extends PerformanceTestCase.Intermediates {
+        public void startTiming(boolean realTime);
+
+        public void addIntermediate(String name);
+
+        public void addIntermediate(String name, long timeInNS);
+
+        public void finishTiming(boolean realTime);
+
+        public void activityFinished(int resultCode, Intent data, RuntimeException where);
+    }
+
+    // Also used as the Binder interface descriptor string in these tests
+    public static final String LAUNCH = "android.app.cts.activity.LAUNCH";
+
+    public static final String FORWARD_RESULT = "android.app.cts.activity.FORWARD_RESULT";
+    public static final String RETURNED_RESULT = "android.app.cts.activity.RETURNED_RESULT";
+
+    public static final String BAD_PARCELABLE = "android.app.cts.activity.BAD_PARCELABLE";
+
+    public static final int LAUNCHED_RESULT = 1;
+    public static final int FORWARDED_RESULT = 2;
+
+    public static final String LIFECYCLE_BASIC = "android.app.cts.activity.LIFECYCLE_BASIC";
+    public static final String LIFECYCLE_SCREEN = "android.app.cts.activity.LIFECYCLE_SCREEN";
+    public static final String LIFECYCLE_DIALOG = "android.app.cts.activity.LIFECYCLE_DIALOG";
+
+    public static final String BROADCAST_REGISTERED = "android.app.cts.activity.BROADCAST_REGISTERED";
+    public static final String BROADCAST_LOCAL = "android.app.cts.activity.BROADCAST_LOCAL";
+    public static final String BROADCAST_REMOTE = "android.app.cts.activity.BROADCAST_REMOTE";
+    public static final String BROADCAST_ALL = "android.app.cts.activity.BROADCAST_ALL";
+    public static final String BROADCAST_REPEAT = "android.app.cts.activity.BROADCAST_REPEAT";
+    public static final String BROADCAST_MULTI = "android.app.cts.activity.BROADCAST_MULTI";
+    public static final String BROADCAST_ABORT = "android.app.cts.activity.BROADCAST_ABORT";
+
+    public static final String EXPANDLIST_SELECT = "EXPANDLIST_SELECT";
+    public static final String EXPANDLIST_VIEW = "EXPANDLIST_VIEW";
+    public static final String EXPANDLIST_CALLBACK = "EXPANDLIST_CALLBACK";
+
+    public static final String BROADCAST_STICKY1 = "android.app.cts.activity.BROADCAST_STICKY1";
+    public static final String BROADCAST_STICKY2 = "android.app.cts.activity.BROADCAST_STICKY2";
+
+    public static final String ALIAS_ACTIVITY = "android.app.cts.activity.ALIAS_ACTIVITY";
+
+    public static final String RECEIVER_REG = "receiver-reg";
+    public static final String RECEIVER_LOCAL = "receiver-local";
+    public static final String RECEIVER_REMOTE = "receiver-remote";
+    public static final String RECEIVER_ABORT = "receiver-abort";
+
+    public static final String DATA_1 = "one";
+    public static final String DATA_2 = "two";
+
+    public static final String ON_START = "onStart";
+    public static final String ON_RESTART = "onRestart";
+    public static final String ON_RESUME = "onResume";
+    public static final String ON_FREEZE = "onSaveInstanceState";
+    public static final String ON_PAUSE = "onPause";
+
+    // ON_STOP and ON_DESTROY are not tested because they may not be called.
+
+    public static final String DO_FINISH = "finish";
+    public static final String DO_LOCAL_SCREEN = "local-screen";
+    public static final String DO_LOCAL_DIALOG = "local-dialog";
+
+    private static final String TAG = "LaunchpadActivity";
+
+    private boolean mBadParcelable = false;
+
+    private boolean mStarted = false;
+
+    private int mResultCode = RESULT_CANCELED;
+    private Intent mData = new Intent().setAction("No result received");
+    private RuntimeException mResultStack = null;
+
+    /** Index into the {@link #mNextLifecycle} array. */
+    private int mNextLifecycle;
+
+    /** Current lifecycle expected to be followed. */
+    private String[] mExpectedLifecycle;
+
+    /** Other possible lifecycles. Never includes the current {@link #mExpectedLifecycle}. */
+    private List<String[]> mOtherPossibleLifecycles = new ArrayList<String[]>(2);
+
+    /** Map from lifecycle arrays to debugging log names. */
+    private Map<String[], String> mLifecycleNames = new HashMap<String[], String>(2);
+
+    private String[] mExpectedReceivers = null;
+    private int mNextReceiver;
+
+    private String[] mExpectedData = null;
+    private boolean[] mReceivedData = null;
+
+    boolean mReceiverRegistered = false;
+
+    private static CallingTest sCallingTest = null;
+
+    public static void setCallingTest(CallingTest ct) {
+        sCallingTest = ct;
+    }
+
+    public LaunchpadActivity() {
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        resetLifecycles();
+
+        // ON_STOP and ON_DESTROY are not tested because they may not be called.
+
+        final String action = getIntent().getAction();
+        if (LIFECYCLE_BASIC.equals(action)) {
+            addPossibleLifecycle(LIFECYCLE_BASIC, new String[] {
+                    ON_START, ON_RESUME, DO_FINISH, ON_PAUSE
+            });
+        } else if (LIFECYCLE_SCREEN.equals(action)) {
+            addPossibleLifecycle(LIFECYCLE_SCREEN + "_RESTART", new String[] {
+                    ON_START, ON_RESUME, DO_LOCAL_SCREEN, ON_PAUSE,
+                    ON_RESTART, ON_START, ON_RESUME, DO_FINISH, ON_PAUSE
+            });
+            addPossibleLifecycle(LIFECYCLE_SCREEN + "_RESUME", new String[] {
+                    ON_START, ON_RESUME, DO_LOCAL_SCREEN, ON_PAUSE,
+                    ON_RESUME, DO_FINISH, ON_PAUSE
+            });
+        } else if (LIFECYCLE_DIALOG.equals(action)) {
+            addPossibleLifecycle(LIFECYCLE_DIALOG + "_RESTART", new String[] {
+                    ON_START, ON_RESUME, DO_LOCAL_DIALOG, ON_PAUSE,
+                    ON_RESTART, ON_START, ON_RESUME, DO_FINISH, ON_PAUSE
+            });
+            addPossibleLifecycle(LIFECYCLE_DIALOG + "_RESUME", new String[] {
+                    ON_START, ON_RESUME, DO_LOCAL_DIALOG, ON_PAUSE,
+                    ON_RESUME, DO_FINISH, ON_PAUSE
+            });
+        }
+    }
+
+    private void resetLifecycles() {
+        mNextLifecycle = 0;
+        mExpectedLifecycle = null;
+        mOtherPossibleLifecycles.clear();
+        mLifecycleNames.clear();
+    }
+
+    /**
+     * Add a potential lifecycle that this activity may follow, since there
+     * are usually multiple valid lifecycles. For instance, sometimes onPause
+     * will lead to onResume rather than onStop when another activity is
+     * raised over the current one.
+     *
+     * @param debugName for the lifecycle shown in the logs
+     * @param lifecycle array containing tokens indicating the expected lifecycle
+     */
+    private void addPossibleLifecycle(String debugName, String[] lifecycle) {
+        mLifecycleNames.put(lifecycle, debugName);
+        if (mExpectedLifecycle == null) {
+            mExpectedLifecycle = lifecycle;
+        } else {
+            mOtherPossibleLifecycles.add(lifecycle);
+        }
+    }
+
+    /**
+     * Switch to the next possible lifecycle and return if switching was
+     * successful. Call this method when mExpectedLifecycle doesn't match
+     * the current lifecycle and you need to check another possible lifecycle.
+     *
+     * @return whether on not there was a lifecycle to switch to
+     */
+    private boolean switchToNextPossibleLifecycle() {
+        if (!mOtherPossibleLifecycles.isEmpty()) {
+            String[] newLifecycle = mOtherPossibleLifecycles.remove(0);
+            Log.w(TAG, "Switching expected lifecycles from "
+                    + mLifecycleNames.get(mExpectedLifecycle) + " to "
+                    + mLifecycleNames.get(newLifecycle));
+            mExpectedLifecycle = newLifecycle;
+            return true;
+        } else {
+            Log.w(TAG, "No more lifecycles after "
+                    + mLifecycleNames.get(mExpectedLifecycle));
+            mExpectedLifecycle = null;
+            return false;
+        }
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        checkLifecycle(ON_START);
+    }
+
+    @Override
+    protected void onRestart() {
+        super.onStart();
+        checkLifecycle(ON_RESTART);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        checkLifecycle(ON_RESUME);
+
+        if (!mStarted) {
+            mStarted = true;
+
+            mHandler.postDelayed(mTimeout, 10 * 1000);
+
+            final String action = getIntent().getAction();
+
+            sCallingTest.startTiming(true);
+
+            if (LAUNCH.equals(action)) {
+                final Intent intent = getIntent();
+                intent.setFlags(0);
+                intent.setComponent((ComponentName) intent.getParcelableExtra("component"));
+                startActivityForResult(intent, LAUNCHED_RESULT);
+
+            } else if (FORWARD_RESULT.equals(action)) {
+                final Intent intent = getIntent();
+                intent.setFlags(0);
+                intent.setClass(this, LocalScreen.class);
+                startActivityForResult(intent, FORWARDED_RESULT);
+            } else if (BAD_PARCELABLE.equals(action)) {
+                mBadParcelable = true;
+                final Intent intent = getIntent();
+                intent.setFlags(0);
+                intent.setClass(this, LocalScreen.class);
+                startActivityForResult(intent, LAUNCHED_RESULT);
+            } else if (BROADCAST_REGISTERED.equals(action)) {
+                setExpectedReceivers(new String[] {
+                    RECEIVER_REG
+                });
+                registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED));
+                sCallingTest.addIntermediate("after-register");
+                sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED));
+            } else if (BROADCAST_LOCAL.equals(action)) {
+                setExpectedReceivers(new String[] {
+                    RECEIVER_LOCAL
+                });
+                sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL));
+            } else if (BROADCAST_REMOTE.equals(action)) {
+                setExpectedReceivers(new String[] {
+                    RECEIVER_REMOTE
+                });
+                sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE));
+            } else if (BROADCAST_ALL.equals(action)) {
+                setExpectedReceivers(new String[] {
+                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL
+                });
+                registerMyReceiver(new IntentFilter(BROADCAST_ALL));
+                sCallingTest.addIntermediate("after-register");
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+            } else if (BROADCAST_MULTI.equals(action)) {
+                setExpectedReceivers(new String[] {
+                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE,
+                        RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE, RECEIVER_REG,
+                        RECEIVER_LOCAL, RECEIVER_LOCAL, RECEIVER_REMOTE, RECEIVER_LOCAL,
+                        RECEIVER_REMOTE, RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE,
+                        RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE, RECEIVER_LOCAL,
+                        RECEIVER_REMOTE, RECEIVER_LOCAL
+                });
+                registerMyReceiver(new IntentFilter(BROADCAST_ALL));
+                sCallingTest.addIntermediate("after-register");
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REPEAT), null);
+            } else if (BROADCAST_ABORT.equals(action)) {
+                setExpectedReceivers(new String[] {
+                        RECEIVER_REMOTE, RECEIVER_ABORT
+                });
+                registerMyReceiver(new IntentFilter(BROADCAST_ABORT));
+                sCallingTest.addIntermediate("after-register");
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ABORT), null);
+            } else if (BROADCAST_STICKY1.equals(action)) {
+                setExpectedReceivers(new String[] {
+                    RECEIVER_REG
+                });
+                setExpectedData(new String[] {
+                    DATA_1
+                });
+                registerMyReceiver(new IntentFilter(BROADCAST_STICKY1));
+                sCallingTest.addIntermediate("after-register");
+            } else if (BROADCAST_STICKY2.equals(action)) {
+                setExpectedReceivers(new String[] {
+                        RECEIVER_REG, RECEIVER_REG
+                });
+                setExpectedData(new String[] {
+                        DATA_1, DATA_2
+                });
+                final IntentFilter filter = new IntentFilter(BROADCAST_STICKY1);
+                filter.addAction(BROADCAST_STICKY2);
+                registerMyReceiver(filter);
+                sCallingTest.addIntermediate("after-register");
+            } else if (ALIAS_ACTIVITY.equals(action)) {
+                final Intent intent = getIntent();
+                intent.setFlags(0);
+                intent.setClass(this, AliasActivityStub.class);
+                startActivityForResult(intent, LAUNCHED_RESULT);
+            } else if (EXPANDLIST_SELECT.equals(action)) {
+                final Intent intent = getIntent();
+                intent.setFlags(0);
+                intent.setAction(action);
+                intent.setComponent((ComponentName) intent.getParcelableExtra("component"));
+                startActivityForResult(intent, LAUNCHED_RESULT);
+            } else if (EXPANDLIST_VIEW.equals(action)) {
+                final Intent intent = getIntent();
+                intent.setFlags(0);
+                intent.setAction(action);
+                intent.setComponent((ComponentName) intent.getParcelableExtra("component"));
+                startActivityForResult(intent, LAUNCHED_RESULT);
+            } else if (EXPANDLIST_CALLBACK.equals(action)) {
+                final Intent intent = getIntent();
+                intent.setFlags(0);
+                intent.setAction(action);
+                intent.setComponent((ComponentName) intent.getParcelableExtra("component"));
+                startActivityForResult(intent, LAUNCHED_RESULT);
+            }
+        }
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle icicle) {
+        super.onSaveInstanceState(icicle);
+        if (mBadParcelable) {
+            icicle.putParcelable("baddy", new MyBadParcelable());
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        checkLifecycle(ON_PAUSE);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        switch (requestCode) {
+            case LAUNCHED_RESULT:
+                sCallingTest.finishTiming(true);
+                finishWithResult(resultCode, data);
+                break;
+            case FORWARDED_RESULT:
+                sCallingTest.finishTiming(true);
+                if (RETURNED_RESULT.equals(data.getAction())) {
+                    finishWithResult(resultCode, data);
+                } else {
+                    finishWithResult(RESULT_CANCELED, new Intent().setAction("Bad data returned: "
+                            + data));
+                }
+                break;
+            default:
+                sCallingTest.finishTiming(true);
+                finishWithResult(RESULT_CANCELED, new Intent()
+                        .setAction("Unexpected request code: " + requestCode));
+                break;
+        }
+    }
+
+    private void checkLifecycle(String where) {
+        String action = getIntent().getAction();
+
+        if (mExpectedLifecycle == null) {
+            return;
+        }
+
+        if (mNextLifecycle >= mExpectedLifecycle.length) {
+            finishBad("Activity lifecycle for " + action + " incorrect: received " + where
+                    + " but don't expect any more calls");
+            mExpectedLifecycle = null;
+            return;
+        }
+
+        do {
+            if (mExpectedLifecycle[mNextLifecycle].equals(where)) {
+                Log.w(TAG, "Matched: " + where);
+                break;
+            } else {
+                Log.w(TAG, "Expected " + mExpectedLifecycle[mNextLifecycle] + " but got " + where);
+            }
+        } while (switchToNextPossibleLifecycle());
+
+        if (mExpectedLifecycle == null) {
+            finishBad("Activity lifecycle for " + action + " incorrect: received " + where
+                    + " at " + mNextLifecycle);
+            return;
+        }
+
+        mNextLifecycle++;
+
+        if (mNextLifecycle >= mExpectedLifecycle.length) {
+            finishGood();
+            return;
+        }
+
+        final String next = mExpectedLifecycle[mNextLifecycle];
+        if (next.equals(DO_FINISH)) {
+            mNextLifecycle++;
+            if (mNextLifecycle >= mExpectedLifecycle.length) {
+                setTestResult(RESULT_OK, null);
+            }
+            if (!isFinishing()) {
+                finish();
+            }
+        } else if (next.equals(DO_LOCAL_SCREEN)) {
+            mNextLifecycle++;
+            final Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
+            intent.setClass(this, LocalScreen.class);
+            startActivity(intent);
+        } else if (next.equals(DO_LOCAL_DIALOG)) {
+            mNextLifecycle++;
+            final Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
+            intent.setClass(this, LocalDialog.class);
+            startActivity(intent);
+        }
+    }
+
+    private void setExpectedReceivers(String[] receivers) {
+        mExpectedReceivers = receivers;
+        mNextReceiver = 0;
+    }
+
+    private void setExpectedData(String[] data) {
+        mExpectedData = data;
+        mReceivedData = new boolean[data.length];
+    }
+
+    @SuppressWarnings("deprecation")
+    private Intent makeBroadcastIntent(String action) {
+        final Intent intent = new Intent(action, null);
+        intent.putExtra("caller", mCallTarget);
+        return intent;
+    }
+
+    private void finishGood() {
+        finishWithResult(RESULT_OK, null);
+    }
+
+    private void finishBad(String error) {
+        finishWithResult(RESULT_CANCELED, new Intent().setAction(error));
+    }
+
+    private void finishWithResult(int resultCode, Intent data) {
+        setTestResult(resultCode, data);
+        finish();
+
+        // Member fields set by calling setTestResult above...
+        sCallingTest.activityFinished(mResultCode, mData, mResultStack);
+    }
+
+    private void setTestResult(int resultCode, Intent data) {
+        mHandler.removeCallbacks(mTimeout);
+        unregisterMyReceiver();
+        mResultCode = resultCode;
+        mData = data;
+        mResultStack = new RuntimeException("Original error was here");
+        mResultStack.fillInStackTrace();
+    }
+
+    private void registerMyReceiver(IntentFilter filter) {
+        mReceiverRegistered = true;
+        registerReceiver(mReceiver, filter);
+    }
+
+    private void unregisterMyReceiver() {
+        if (mReceiverRegistered) {
+            mReceiverRegistered = false;
+            unregisterReceiver(mReceiver);
+        }
+    }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+        }
+    };
+
+    static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
+    static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1;
+
+    private final Binder mCallTarget = new Binder() {
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
+            data.setDataPosition(0);
+            data.enforceInterface(LaunchpadActivity.LAUNCH);
+            if (code == GOT_RECEIVE_TRANSACTION) {
+                final String name = data.readString();
+                gotReceive(name, null);
+                return true;
+            } else if (code == ERROR_TRANSACTION) {
+                finishBad(data.readString());
+                return true;
+            }
+            return false;
+        }
+    };
+
+    private final void gotReceive(String name, Intent intent) {
+        synchronized (this) {
+
+            sCallingTest.addIntermediate(mNextReceiver + "-" + name);
+
+            if (mExpectedData != null) {
+                final int n = mExpectedData.length;
+                int i;
+                boolean prev = false;
+                for (i = 0; i < n; i++) {
+                    if (mExpectedData[i].equals(intent.getStringExtra("test"))) {
+                        if (mReceivedData[i]) {
+                            prev = true;
+                            continue;
+                        }
+                        mReceivedData[i] = true;
+                        break;
+                    }
+                }
+                if (i >= n) {
+                    if (prev) {
+                        finishBad("Receive got data too many times: "
+                                + intent.getStringExtra("test"));
+                    } else {
+                        finishBad("Receive got unexpected data: " + intent.getStringExtra("test"));
+                    }
+                    return;
+                }
+            }
+
+            if (mNextReceiver >= mExpectedReceivers.length) {
+                finishBad("Got too many onReceiveIntent() calls!");
+            } else if (!mExpectedReceivers[mNextReceiver].equals(name)) {
+                finishBad("Receive out of order: got " + name + " but expected "
+                        + mExpectedReceivers[mNextReceiver] + " at " + mNextReceiver);
+            } else {
+                mNextReceiver++;
+                if (mNextReceiver == mExpectedReceivers.length) {
+                    mHandler.post(mUnregister);
+                }
+            }
+
+        }
+    }
+
+    private final Runnable mUnregister = new Runnable() {
+        public void run() {
+            if (mReceiverRegistered) {
+                sCallingTest.addIntermediate("before-unregister");
+                unregisterMyReceiver();
+            }
+            sCallingTest.finishTiming(true);
+            finishGood();
+        }
+    };
+
+    private final Runnable mTimeout = new Runnable() {
+        public void run() {
+            Log.i(TAG, "timeout");
+            String msg = "Timeout";
+            if (mExpectedReceivers != null && mNextReceiver < mExpectedReceivers.length) {
+                msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver];
+            }
+            finishBad(msg);
+        }
+    };
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            gotReceive(RECEIVER_REG, intent);
+        }
+    };
+}
diff --git a/tests/app/app/src/android/app/stubs/LaunchpadTabActivity.java b/tests/app/app/src/android/app/stubs/LaunchpadTabActivity.java
new file mode 100644
index 0000000..a63b384
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LaunchpadTabActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.TabActivity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.TabHost;
+
+public class LaunchpadTabActivity extends TabActivity {
+    public LaunchpadTabActivity() {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        final Intent tabIntent = new Intent(getIntent());
+        tabIntent.setComponent((ComponentName) tabIntent.getParcelableExtra("tab"));
+
+        final TabHost th = getTabHost();
+        final TabHost.TabSpec ts = th.newTabSpec("1");
+        ts.setIndicator("One");
+        ts.setContent(tabIntent);
+        th.addTab(ts);
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/LocalActivity.java b/tests/app/app/src/android/app/stubs/LocalActivity.java
new file mode 100644
index 0000000..b279d3b
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+public class LocalActivity extends TestedActivity {
+    public LocalActivity() {
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/LocalActivityManagerStubActivity.java b/tests/app/app/src/android/app/stubs/LocalActivityManagerStubActivity.java
new file mode 100644
index 0000000..f7df9a3
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalActivityManagerStubActivity.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class LocalActivityManagerStubActivity extends Activity{
+
+    public static boolean sIsOnResumeCalled;
+    public static boolean sIsOnStopCalled;
+    public static boolean sIsOnPauseCalled;
+    public static boolean sIsOnDestroyCalled;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        sIsOnResumeCalled = true;
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        sIsOnStopCalled = true;
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        sIsOnPauseCalled = true;
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        sIsOnDestroyCalled = true;
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java b/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java
new file mode 100644
index 0000000..8e28ee4
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.app.stubs;
+
+
+import android.app.Activity;
+import android.app.ActivityGroup;
+import android.app.LocalActivityManager;
+import android.content.Intent;
+import android.cts.util.CTSResult;
+import android.os.Bundle;
+import android.view.Window;
+
+public class LocalActivityManagerTestHelper extends ActivityGroup {
+
+    public static final String ACTION_DISPATCH_RESUME = "dispatchResume";
+    public static final String ACTION_START_ACTIVITY = "startActivity";
+    public static final String ACTION_DISPATCH_CREATE = "dispatchCreate";
+    public static final String ACTION_DISPATCH_STOP = "dispatchStop";
+    public static final String ACTION_DISPATCH_PAUSE_TRUE = "dispatchPauseTrue";
+    public static final String ACTION_DISPATCH_PAUSE_FALSE = "dispatchPauseFalse";
+    public static final String ACTION_SAVE_INSTANCE_STATE = "saveInstanceState";
+    public static final String ACTION_DISPATCH_DESTROY = "dispatchDestroy";
+    public static final String ACTION_REMOVE_ALL_ACTIVITY = "removeAllActivities";
+
+    private String mCurrentAction;
+    private LocalActivityManager mLocalActivityManager;
+
+    private static CTSResult sResult;
+
+    public static void setResult(CTSResult cr) {
+        sResult = cr;
+    }
+
+    public LocalActivityManagerTestHelper() {
+        super();
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mCurrentAction = getIntent().getAction();
+        mLocalActivityManager = getLocalActivityManager();
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+    }
+
+    protected void onResume() {
+        super.onResume();
+        if (mCurrentAction.equals(ACTION_DISPATCH_RESUME)) {
+            testDispatchResume();
+        } else if (mCurrentAction.equals(ACTION_START_ACTIVITY)) {
+            testStartActivity();
+        } else if (mCurrentAction.equals(ACTION_DISPATCH_CREATE)) {
+            testDispatchCreate();
+        } else if (mCurrentAction.equals(ACTION_DISPATCH_STOP)) {
+            testDispatchStop();
+        } else if (mCurrentAction.equals(ACTION_DISPATCH_PAUSE_TRUE)) {
+            testDispatchPauseTrue();
+        } else if (mCurrentAction.equals(ACTION_DISPATCH_PAUSE_FALSE)) {
+            testDispatchPauseFalse();
+        } else if (mCurrentAction.equals(ACTION_SAVE_INSTANCE_STATE)) {
+            testSaveInstanceState();
+        } else if (mCurrentAction.equals(ACTION_DISPATCH_DESTROY)) {
+            testDispatchDestroy();
+        } else if (mCurrentAction.equals(ACTION_REMOVE_ALL_ACTIVITY)) {
+            testRemoveAllActivity();
+        }
+    }
+
+    private void testRemoveAllActivity() {
+        final String id = "id_remove_activity";
+        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mLocalActivityManager.startActivity(id, intent);
+
+        Activity activity = mLocalActivityManager.getActivity(id);
+        if (activity == null) {
+            fail();
+            return;
+        }
+
+        if (!activity.getClass().getName().equals("android.app.stubs."
+                    + "LocalActivityManagerStubActivity")) {
+            fail();
+            return;
+        }
+
+        mLocalActivityManager.removeAllActivities();
+        activity = mLocalActivityManager.getActivity(id);
+        if (activity != null) {
+            fail();
+            return;
+        }
+        pass();
+    }
+
+    private void testDispatchDestroy() {
+        final String id1 = "id_dispatch_destroy1";
+        final String id2 = "id_dispatch_destroy2";
+        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mLocalActivityManager.startActivity(id1, intent);
+
+        LocalActivityManagerStubActivity.sIsOnDestroyCalled = false;
+        mLocalActivityManager.dispatchDestroy(false);
+        if (mLocalActivityManager.getCurrentActivity().isFinishing()){
+            fail();
+            return;
+        }
+
+        if (!LocalActivityManagerStubActivity.sIsOnDestroyCalled) {
+            fail();
+            return;
+        }
+
+        mLocalActivityManager.startActivity(id2, intent);
+        LocalActivityManagerStubActivity.sIsOnDestroyCalled = false;
+        mLocalActivityManager.dispatchDestroy(true);
+
+        if (!LocalActivityManagerStubActivity.sIsOnDestroyCalled) {
+            fail();
+            return;
+        }
+
+        if (!mLocalActivityManager.getCurrentActivity().isFinishing()){
+            fail();
+            return;
+        }
+        pass();
+    }
+
+    private void testSaveInstanceState() {
+        final String key = "_id1";
+        mLocalActivityManager.dispatchCreate(null);
+        final Bundle bundle = mLocalActivityManager.saveInstanceState();
+        if (bundle != null) {
+            fail();
+            return;
+        }
+
+        final String id = "id_dispatch_pause";
+        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mLocalActivityManager.startActivity(id, intent);
+
+        final Bundle savedBundle = new Bundle();
+        final Bundle bb = new Bundle();
+        savedBundle.putBundle(key, bb);
+
+        mLocalActivityManager.dispatchCreate(savedBundle);
+        final Bundle returnedBundle = mLocalActivityManager.saveInstanceState();
+        if (returnedBundle.getBundle(key) == null ) {
+            fail();
+            return;
+        }
+        pass();
+    }
+
+    private void testDispatchPauseFalse() {
+        final String id = "id_dispatch_pause";
+        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mLocalActivityManager.startActivity(id, intent);
+        LocalActivityManagerStubActivity.sIsOnPauseCalled = false;
+        mLocalActivityManager.dispatchPause(false);
+        if (!LocalActivityManagerStubActivity.sIsOnPauseCalled) {
+            fail();
+            return;
+        }
+        pass();
+    }
+
+    private void testDispatchPauseTrue() {
+        final String id = "id_dispatch_pause";
+        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mLocalActivityManager.startActivity(id, intent);
+        LocalActivityManagerStubActivity.sIsOnPauseCalled = false;
+        mLocalActivityManager.dispatchPause(true);
+        if (!LocalActivityManagerStubActivity.sIsOnPauseCalled) {
+            fail();
+            return;
+        }
+        pass();
+    }
+
+    private void testDispatchStop() {
+        final String id = "id_dispatch_stop";
+        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mLocalActivityManager.startActivity(id, intent);
+        if (mLocalActivityManager.getCurrentActivity() == null) {
+            fail();
+            return;
+        }
+
+        LocalActivityManagerStubActivity.sIsOnStopCalled = false;
+        mLocalActivityManager.dispatchStop();
+
+        if (!LocalActivityManagerStubActivity.sIsOnStopCalled) {
+            fail();
+            return;
+        }
+        pass();
+    }
+
+    private void testDispatchCreate() {
+        final Bundle EXPECTED = new Bundle();
+        final String id = "id";
+
+        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mLocalActivityManager.startActivity("_id" + System.currentTimeMillis(), intent);
+        final Bundle bundle = mLocalActivityManager.saveInstanceState();
+        if (bundle == null) {
+            fail();
+            return;
+        }
+
+        if (bundle.keySet().size() != 1) {
+            fail();
+            return;
+        }
+
+        bundle.putBundle(id, EXPECTED);
+        // test null parameter
+        mLocalActivityManager.dispatchCreate(null);
+
+        if (mLocalActivityManager.saveInstanceState().keySet().size() != 1) {
+            fail();
+            return;
+        }
+
+        mLocalActivityManager.dispatchCreate(bundle);
+
+        final Bundle b = mLocalActivityManager.saveInstanceState();
+        final Bundle bb = b.getBundle(id);
+        if (bb != EXPECTED) {
+            fail();
+            return;
+        }
+        pass();
+    }
+
+    private void testStartActivity() {
+        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        final String id = "_id_resume_test";
+        final Window w = mLocalActivityManager.startActivity(id, intent);
+        if (w == null) {
+            fail();
+            return;
+        }
+
+        Activity activity = mLocalActivityManager.getActivity(id);
+        if (activity == null) {
+            fail();
+            return;
+        }
+
+        // testing null id
+        activity = mLocalActivityManager.getActivity("null id");
+        if (activity != null) {
+            fail();
+            return;
+        }
+
+        if (!mLocalActivityManager.getCurrentId().equals(id)) {
+            fail();
+            return;
+        }
+
+        if (mLocalActivityManager.getActivity(id) != mLocalActivityManager
+                .getCurrentActivity()) {
+            fail();
+            return;
+        }
+
+        if (mLocalActivityManager.destroyActivity(id, true) == null) {
+            fail();
+            return;
+        }
+
+        if (mLocalActivityManager.startActivity(null, intent) == null) {
+            fail();
+            return;
+        }
+
+        try {
+            // test when calling startActivity with both null parameter.
+            mLocalActivityManager.startActivity(null, null);
+            fail();
+            return;
+        } catch (NullPointerException e) {
+        }
+        pass();
+    }
+
+    private void testDispatchResume() {
+        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mLocalActivityManager.startActivity("_id_resume_test", intent);
+        mLocalActivityManager.dispatchStop();
+        LocalActivityManagerStubActivity.sIsOnResumeCalled = false;
+        mLocalActivityManager.dispatchResume();
+        if (LocalActivityManagerStubActivity.sIsOnResumeCalled) {
+            pass();
+        } else {
+            fail();
+        }
+    }
+
+    private void fail() {
+        sResult.setResult(CTSResult.RESULT_FAIL);
+        finish();
+    }
+
+    private void pass() {
+        sResult.setResult(CTSResult.RESULT_OK);
+        finish();
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/LocalDeniedService.java b/tests/app/app/src/android/app/stubs/LocalDeniedService.java
new file mode 100644
index 0000000..aaf4670
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalDeniedService.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+public class LocalDeniedService extends LocalService
+{
+}
+
diff --git a/tests/app/app/src/android/app/stubs/LocalDialog.java b/tests/app/app/src/android/app/stubs/LocalDialog.java
new file mode 100644
index 0000000..62c4824
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalDialog.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+public class LocalDialog extends TestedScreen {
+    public LocalDialog() {
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/LocalGrantedService.java b/tests/app/app/src/android/app/stubs/LocalGrantedService.java
new file mode 100644
index 0000000..c82d3fd
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalGrantedService.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+public class LocalGrantedService extends LocalService
+{
+}
+
diff --git a/tests/app/app/src/android/app/stubs/LocalScreen.java b/tests/app/app/src/android/app/stubs/LocalScreen.java
new file mode 100644
index 0000000..21026a1
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalScreen.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+public class LocalScreen extends TestedScreen {
+    public LocalScreen() {
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/LocalService.java b/tests/app/app/src/android/app/stubs/LocalService.java
new file mode 100644
index 0000000..01e098b
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalService.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Service;
+import android.content.Intent;
+import android.cts.util.IBinderParcelable;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+public class LocalService extends Service {
+    public static final String SERVICE_LOCAL =
+            "android.app.cts.activity.SERVICE_LOCAL";
+    public static final String SERVICE_LOCAL_GRANTED =
+            "android.app.cts.activity.SERVICE_LOCAL_GRANTED";
+    public static final String SERVICE_LOCAL_DENIED =
+            "android.app.cts.activity.SERVICE_LOCAL_DENIED";
+
+    public static final String REPORT_OBJ_NAME = "report";
+
+    public static final int STARTED_CODE = 1;
+    public static final int DESTROYED_CODE = 2;
+    public static final int SET_REPORTER_CODE = 3;
+    public static final int UNBIND_CODE = 4;
+    public static final int REBIND_CODE = 5;
+
+    private IBinder mReportObject;
+    private int mStartCount = 1;
+
+    private final IBinder mBinder = new Binder() {
+        @Override
+        protected boolean onTransact(int code, Parcel data, Parcel reply,
+                int flags) throws RemoteException {
+            if (code == SET_REPORTER_CODE) {
+                data.enforceInterface(SERVICE_LOCAL);
+                mReportObject = data.readStrongBinder();
+                return true;
+            } else {
+                return super.onTransact(code, data, reply, flags);
+            }
+        }
+    };
+
+
+    public LocalService() {
+    }
+
+    @Override
+    public void onStart(Intent intent, int startId) {
+        if (intent.getExtras() != null) {
+            IBinderParcelable parcelable
+                    = (IBinderParcelable) intent.getExtras().getParcelable(REPORT_OBJ_NAME);
+            mReportObject = parcelable.binder;
+            if (mReportObject != null) {
+                bindAction(STARTED_CODE);
+            }
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mReportObject != null) {
+            bindAction(DESTROYED_CODE);
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        if (mReportObject != null) {
+            bindAction(UNBIND_CODE);
+        }
+        return true;
+    }
+
+    @Override
+    public void onRebind(Intent intent) {
+        if (mReportObject != null) {
+            bindAction(REBIND_CODE);
+        }
+    }
+
+    private void bindAction(final int bindCode) {
+        try {
+            Parcel data = Parcel.obtain();
+            data.writeInterfaceToken(SERVICE_LOCAL);
+            if (bindCode == STARTED_CODE) {
+                data.writeInt(mStartCount);
+                mStartCount++;
+            }
+            mReportObject.transact(
+                    bindCode, data, null, 0);
+            data.recycle();
+        } catch (RemoteException e) {
+            // fail
+        }
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/MockActivity.java b/tests/app/app/src/android/app/stubs/MockActivity.java
new file mode 100644
index 0000000..625263a
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/MockActivity.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+
+public class MockActivity extends Activity {
+
+}
diff --git a/tests/app/app/src/android/app/stubs/MockAlarmReceiver.java b/tests/app/app/src/android/app/stubs/MockAlarmReceiver.java
new file mode 100644
index 0000000..57374ef
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/MockAlarmReceiver.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.SystemClock;
+
+/**
+ * this class  receive alarm from AlarmManagerTest
+ */
+public class MockAlarmReceiver extends BroadcastReceiver {
+    private final Object mSync = new Object();
+    public final String mTargetAction;
+
+    public volatile boolean alarmed = false;
+    public volatile long elapsedTime;
+    public volatile long rtcTime;
+
+    public MockAlarmReceiver(String targetAction) {
+        mTargetAction = targetAction;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(mTargetAction)) {
+            synchronized (mSync) {
+                alarmed = true;
+                elapsedTime = SystemClock.elapsedRealtime();
+                rtcTime = System.currentTimeMillis();
+            }
+        }
+    }
+
+    public void setAlarmedFalse() {
+        synchronized (mSync) {
+            alarmed = false;
+        }
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/MockApplication.java b/tests/app/app/src/android/app/stubs/MockApplication.java
new file mode 100644
index 0000000..4de2a95
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/MockApplication.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Application;
+import android.content.res.Configuration;
+
+
+public class MockApplication extends Application {
+
+    public boolean isOnCreateCalled;
+    public boolean isConstructorCalled;
+    public boolean isOnConfigurationChangedCalled;
+    public boolean isOnLowMemoryCalled;
+
+    public MockApplication() {
+        super();
+        isConstructorCalled = true;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        isOnCreateCalled = true;
+    }
+
+    @Override
+    public void onTerminate() {
+        super.onTerminate();
+        // The documentation states that one cannot rely on this method being called. No need to
+        // test it here.
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        isOnConfigurationChangedCalled = true;
+    }
+
+    @Override
+    public void onLowMemory() {
+        super.onLowMemory();
+        isOnLowMemoryCalled = true;
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/MockApplicationActivity.java b/tests/app/app/src/android/app/stubs/MockApplicationActivity.java
new file mode 100644
index 0000000..6df70d7
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/MockApplicationActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class MockApplicationActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        TextView textView = new TextView(this);
+        textView.setText("Test");
+        setContentView(textView);
+    }
+
+}
diff --git a/tests/app/app/src/android/app/stubs/MockReceiver.java b/tests/app/app/src/android/app/stubs/MockReceiver.java
new file mode 100644
index 0000000..7704340
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/MockReceiver.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class MockReceiver extends BroadcastReceiver {
+
+    // PendingIntent may return same instance or new instance, so static variable is needed.
+    public static int sResultCode = 0;
+    public static final String MOCKACTION = "android.app.PendingIntentTest.TEST_RECEIVER";
+    public static String sAction;
+
+    /**
+     * set the result as true when received alarm
+     */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        sAction = intent.getAction();
+        if (sAction.equals(MOCKACTION)) {
+            sResultCode = getResultCode();
+        }
+    }
+}
+
diff --git a/tests/app/app/src/android/app/stubs/MockService.java b/tests/app/app/src/android/app/stubs/MockService.java
new file mode 100644
index 0000000..7a8c001
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/MockService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+public class MockService extends Service {
+    public static boolean result = false;
+    private final IBinder mBinder = new MockBinder();
+
+    public class MockBinder extends Binder {
+        MockService getService() {
+            return MockService.this;
+        }
+    }
+
+    /**
+     * set the result as true when service bind
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        result = true;
+        return mBinder;
+    }
+
+    /**
+     * set the result as true when service start
+     */
+    @Override
+    public void onStart(Intent intent, int startId) {
+        super.onStart(intent, startId);
+        result = true;
+    }
+}
+
diff --git a/tests/app/app/src/android/app/stubs/MockTabActivity.java b/tests/app/app/src/android/app/stubs/MockTabActivity.java
new file mode 100644
index 0000000..247cfe0
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/MockTabActivity.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.app.TabActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.TabHost;
+
+public class MockTabActivity extends TabActivity {
+
+    private static final String TAB1 = "tab1";
+    private static final String TAB2 = "tab2";
+    private static final String TAB3 = "tab3";
+
+    public boolean isOnChildTitleChangedCalled;
+    public boolean isOnPostCreateCalled;
+    public boolean isOnSaveInstanceStateCalled;
+    public boolean isOnContentChangedCalled;
+    public static boolean isOnRestoreInstanceStateCalled;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final TabHost tabHost = getTabHost();
+
+        tabHost.addTab(tabHost.newTabSpec(TAB1).setIndicator(TAB1)
+                .setContent(new Intent(this, ChildTabActivity.class)));
+
+        tabHost.addTab(tabHost.newTabSpec(TAB2).setIndicator(TAB2)
+                .setContent(new Intent(this, MockActivity.class)));
+
+        tabHost.addTab(tabHost.newTabSpec(TAB3).setIndicator(TAB3).setContent(
+                new Intent(this, AppStubActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)));
+
+    }
+
+    @Override
+    protected void onChildTitleChanged(Activity childActivity, CharSequence title) {
+        super.onChildTitleChanged(childActivity, title);
+        isOnChildTitleChangedCalled = true;
+    }
+
+    @Override
+    protected void onPostCreate(Bundle icicle) {
+        super.onPostCreate(icicle);
+        isOnPostCreateCalled = true;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle state) {
+        super.onRestoreInstanceState(state);
+        isOnRestoreInstanceStateCalled = true;
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        isOnSaveInstanceStateCalled = true;
+    }
+
+    @Override
+    public void onContentChanged() {
+        super.onContentChanged();
+        isOnContentChangedCalled = true;
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/OrientationTestUtils.java b/tests/app/app/src/android/app/stubs/OrientationTestUtils.java
new file mode 100644
index 0000000..4ff3fcb
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/OrientationTestUtils.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.pm.ActivityInfo;
+
+public class OrientationTestUtils {
+
+    /**
+     * Change the activity's orientation to something different and then switch back. This is used
+     * to trigger {@link Activity#onConfigurationChanged(android.content.res.Configuration)}.
+     *
+     * @param activity whose orientation will be changed and restored
+     */
+    public static void toggleOrientation(Activity activity) {
+        toggleOrientationSync(activity, null);
+    }
+
+    /**
+     * Same as {@link #toggleOrientation(Activity)} except {@link Instrumentation#waitForIdleSync()}
+     * is called after each orientation change.
+     *
+     * @param activity whose orientation will be changed and restored
+     * @param instrumentation use for idle syncing
+     */
+    public static void toggleOrientationSync(final Activity activity,
+            final Instrumentation instrumentation) {
+        final int originalOrientation = activity.getResources().getConfiguration().orientation;
+        final int newOrientation = originalOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+                ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+                : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+        changeOrientation(activity, instrumentation, newOrientation);
+        changeOrientation(activity, instrumentation, originalOrientation);
+    }
+
+    private static void changeOrientation(final Activity activity,
+            Instrumentation instrumentation, final int orientation) {
+        activity.setRequestedOrientation(orientation);
+        if (instrumentation != null) {
+            instrumentation.waitForIdleSync();
+        }
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/PendingIntentStubActivity.java b/tests/app/app/src/android/app/stubs/PendingIntentStubActivity.java
new file mode 100644
index 0000000..00b59d1
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/PendingIntentStubActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class PendingIntentStubActivity extends Activity {
+
+    public static final int INVALIDATE = -1;
+    public static final int ON_CREATE = 0;
+    public static int status = INVALIDATE;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        status = ON_CREATE;
+    }
+
+}
diff --git a/tests/app/app/src/android/app/stubs/PipActivity.java b/tests/app/app/src/android/app/stubs/PipActivity.java
new file mode 100644
index 0000000..533f054
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/PipActivity.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+
+public class PipActivity extends Activity {
+
+}
diff --git a/tests/app/app/src/android/app/stubs/PipNotResizeableActivity.java b/tests/app/app/src/android/app/stubs/PipNotResizeableActivity.java
new file mode 100644
index 0000000..7ed1acc
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/PipNotResizeableActivity.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+
+public class PipNotResizeableActivity extends Activity {
+
+}
diff --git a/tests/app/app/src/android/app/stubs/PipNotSupportedActivity.java b/tests/app/app/src/android/app/stubs/PipNotSupportedActivity.java
new file mode 100644
index 0000000..e6656a0
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/PipNotSupportedActivity.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+
+public class PipNotSupportedActivity extends Activity {
+
+}
diff --git a/tests/app/app/src/android/app/stubs/SearchManagerStubActivity.java b/tests/app/app/src/android/app/stubs/SearchManagerStubActivity.java
new file mode 100644
index 0000000..d6eb968
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/SearchManagerStubActivity.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.app.SearchManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.cts.util.CTSResult;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+public class SearchManagerStubActivity extends Activity {
+
+    private static final String TAG = "SearchManagerStubActivity";
+
+    public static final String TEST_STOP_SEARCH = "stopSearch";
+    public static final String TEST_ON_DISMISSLISTENER = "setOnDismissListener";
+    public static final String TEST_ON_CANCELLISTENER = "setOnCancelListener";
+
+    private SearchManager mSearchManager;
+    private ComponentName mComponentName;
+
+    private static CTSResult sCTSResult;
+    private boolean mDismissCalled;
+    private boolean mCancelCalled;
+
+    public static void setCTSResult(CTSResult result) {
+        sCTSResult = result;
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        mSearchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
+        mComponentName = getComponentName();
+        String action = getIntent().getAction();
+        if (action.equals(TEST_STOP_SEARCH)) {
+            testStopSearch();
+        } else if (action.equals(TEST_ON_DISMISSLISTENER)) {
+            testOnDismissListener();
+        } else if (action.equals(TEST_ON_CANCELLISTENER)) {
+            testOnCancelListener();
+        }
+    }
+
+    private void testOnCancelListener() {
+        mCancelCalled = false;
+        mSearchManager.setOnCancelListener(new SearchManager.OnCancelListener() {
+            @Override
+            public void onCancel() {
+               mCancelCalled = true;
+            }
+        });
+
+        new TestStepHandler() {
+            @Override
+            public boolean doStep(int step) throws FailException {
+                switch (step) {
+                    case 1:
+                        startSearch("test", false, mComponentName, null, false);
+                        return false;
+                    case 2:
+                        assertFalse("cancel called", mCancelCalled);
+                        stopSearch();
+                        return false;
+                    case 3:
+                        assertTrue("cancel not called", mCancelCalled);
+                        pass();
+                        return true;
+                    default:
+                        throw new IllegalArgumentException("Bad step " + step);
+                }
+            }
+        }.start();
+    }
+
+    private void testOnDismissListener() {
+        mDismissCalled = false;
+
+        mSearchManager.setOnDismissListener(new SearchManager.OnDismissListener() {
+            public void onDismiss() {
+                mDismissCalled = true;
+            }
+        });
+
+        new TestStepHandler() {
+            @Override
+            public boolean doStep(int step) throws FailException {
+                switch (step) {
+                    case 1:
+                        startSearch("test", false, mComponentName, null, false);
+                        return false;
+                    case 2:
+                        if (mDismissCalled) {
+                            throw new FailException("dismiss called");
+                        } else {
+                            stopSearch();
+                        }
+                        return false;
+                    case 3:
+                        if (mDismissCalled) {
+                            pass();
+                        } else {
+                            throw new FailException("dismiss not called");
+                        }
+                        return true;
+                    default:
+                        throw new IllegalArgumentException("Bad step " + step);
+                }
+            }
+        }.start();
+    }
+
+    private void testStopSearch() {
+        new TestStepHandler() {
+            @Override
+            public boolean doStep(int step) throws FailException {
+                switch (step) {
+                    case 1:
+                        startSearch("test", false, mComponentName, null, false);
+                        return false;
+                    case 2:
+                        assertVisible();
+                        stopSearch();
+                        return false;
+                    case 3:
+                        assertInVisible();
+                        pass();
+                        return true;
+                    default:
+                        throw new IllegalArgumentException("Bad step " + step);
+                }
+            }
+        }.start();
+    }
+
+    private void fail(Exception ex) {
+        Log.e(TAG, "test failed", ex);
+        sCTSResult.setResult(CTSResult.RESULT_FAIL);
+        finish();
+    }
+
+    private void pass() {
+        sCTSResult.setResult(CTSResult.RESULT_OK);
+        finish();
+    }
+
+    private void assertInVisible() throws FailException {
+        if (isVisible()) {
+            throw new FailException();
+        }
+    }
+
+    private void assertVisible() throws FailException {
+        if (!isVisible()) {
+            throw new FailException();
+        }
+    }
+
+    private void assertFalse(String message, boolean value) throws FailException {
+        assertTrue(message, !value);
+    }
+
+    private void assertTrue(String message, boolean value) throws FailException {
+        if (!value) {
+            throw new FailException(message);
+        }
+    }
+
+    private void startSearch(String initialQuery, boolean selectInitialQuery,
+            ComponentName launchActivity, Bundle appSearchData, boolean globalSearch) {
+        mSearchManager.startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData,
+                globalSearch);
+    }
+
+    private void stopSearch() {
+       mSearchManager.stopSearch();
+    }
+
+    private boolean isVisible() {
+        return mSearchManager.isVisible();
+    }
+
+    private abstract class TestStepHandler extends Handler {
+
+        public void start() {
+            sendEmptyMessage(1);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            try {
+                if (!doStep(msg.what)) {
+                    sendEmptyMessage(msg.what + 1);
+                }
+            } catch (FailException ex) {
+                fail(ex);
+            }
+        }
+
+        /**
+         * Performs one step of the test.
+         *
+         * @param step The 1-based number of the step to perform.
+         * @return {@code true} if this was the last step.
+         * @throws FailException If the test failed.
+         */
+        protected abstract boolean doStep(int step) throws FailException;
+    }
+
+    private static class FailException extends Exception {
+        private static final long serialVersionUID = 1L;
+
+        public FailException() {
+            super();
+        }
+
+        public FailException(String detailMessage) {
+            super(detailMessage);
+        }
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/StubRemoteService.java b/tests/app/app/src/android/app/stubs/StubRemoteService.java
new file mode 100644
index 0000000..4fde60b
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/StubRemoteService.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Process;
+
+public class StubRemoteService extends Service{
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        android.util.Log.d("Process test stub", "StubRemoteServiceProcessPid:" + Process.myPid());
+    }
+
+    private final ISecondary.Stub mSecondaryBinder = new ISecondary.Stub() {
+        public int getPid() {
+            return Process.myPid();
+        }
+
+        public long getElapsedCpuTime() {
+            return Process.getElapsedCpuTime();
+        }
+
+        public String getTimeZoneID() {
+            return java.util.TimeZone.getDefault().getID();
+        }
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (ISecondary.class.getName().equals(intent.getAction())) {
+            return mSecondaryBinder;
+        }
+        return null;
+    }
+
+}
diff --git a/tests/app/app/src/android/app/stubs/TestDialog.java b/tests/app/app/src/android/app/stubs/TestDialog.java
new file mode 100644
index 0000000..e404e65
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/TestDialog.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.stubs;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.WindowManager.LayoutParams;
+
+public class TestDialog extends Dialog {
+    private static final int OPTIONS_MENU_ITEM_0 = Menu.FIRST;
+    private static final int OPTIONS_MENU_ITEM_1 = Menu.FIRST + 1;
+    private static final int OPTIONS_MENU_ITEM_2 = Menu.FIRST + 2;
+    private static final int OPTIONS_MENU_ITEM_3 = Menu.FIRST + 3;
+    private static final int OPTIONS_MENU_ITEM_4 = Menu.FIRST + 4;
+    private static final int OPTIONS_MENU_ITEM_5 = Menu.FIRST + 5;
+    private static final int OPTIONS_MENU_ITEM_6 = Menu.FIRST + 6;
+    private static final int CONTEXT_MENU_ITEM_0 = Menu.FIRST + 7;
+    private static final int CONTEXT_MENU_ITEM_1 = Menu.FIRST + 8;
+    private static final int CONTEXT_MENU_ITEM_2 = Menu.FIRST + 9;
+    public boolean isOnStartCalled;
+    public boolean isOnStopCalled;
+    public boolean isOnCreateCalled;
+    public boolean isRequestWindowFeature;
+    public boolean isOnContentChangedCalled;
+    public boolean isOnWindowFocusChangedCalled;
+    public boolean isOnTouchEventCalled;
+    public boolean isOnTrackballEventCalled;
+    public boolean isOnKeyDownCalled;
+    public boolean isOnKeyUpCalled;
+    public boolean isOnKeyMultipleCalled;
+    public boolean isOnSaveInstanceStateCalled;
+    public static boolean isOnRestoreInstanceStateCalled;
+    public boolean isOnWindowAttributesChangedCalled;
+    public boolean isOnCreatePanelMenuCalled;
+    public boolean isOnCreatePanelViewCalled;
+    public boolean isOnPreparePanelCalled;
+    public boolean isOnMenuOpenedCalled;
+    public boolean isOnMenuItemSelectedCalled;
+    public boolean isOnPanelClosedCalled;
+    public boolean isOnCreateOptionsMenuCalled;
+    public boolean isOnPrepareOptionsMenuCalled;
+    public boolean isOnOptionsItemSelectedCalled;
+    public boolean isOnOptionsMenuClosedCalled;
+    public boolean isOnContextItemSelectedCalled;
+    public boolean isOnContextMenuClosedCalled;
+    public boolean isOnCreateContextMenuCalled;
+    public boolean isOnSearchRequestedCalled;
+    public boolean onKeyDownReturn;
+    public boolean onKeyMultipleReturn;
+    public boolean dispatchTouchEventResult;
+    public boolean dispatchKeyEventResult;
+    public int keyDownCode = -1;
+    public Window window;
+    public Bundle saveInstanceState;
+    public Bundle savedInstanceState;
+    public KeyEvent keyEvent;
+    public MotionEvent touchEvent;
+    public MotionEvent trackballEvent;
+    public MotionEvent onTrackballEvent;
+    public MotionEvent onTouchEvent;
+    public KeyEvent keyMultipleEvent;
+
+    public TestDialog(Context context) {
+        super(context);
+    }
+
+    public TestDialog(Context context, int theme) {
+        super(context, theme);
+    }
+
+    public TestDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
+        super(context, cancelable, cancelListener);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        isOnStartCalled = true;
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        isOnStopCalled = true;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        isRequestWindowFeature = requestWindowFeature(Window.FEATURE_LEFT_ICON);
+        super.onCreate(savedInstanceState);
+        isOnCreateCalled = true;
+    }
+
+    @Override
+    public void onContentChanged() {
+        super.onContentChanged();
+
+        isOnContentChangedCalled = true;
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+
+        isOnWindowFocusChangedCalled = true;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        isOnTouchEventCalled = true;
+        onTouchEvent = event;
+        return super.onTouchEvent(event);
+    }
+
+    @Override
+    public boolean onTrackballEvent(MotionEvent event) {
+        isOnTrackballEventCalled = true;
+        onTrackballEvent = event;
+        return super.onTrackballEvent(event);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        isOnKeyDownCalled = true;
+        keyDownCode = keyCode;
+        onKeyDownReturn = super.onKeyDown(keyCode, event);
+
+        return onKeyDownReturn;
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        isOnKeyUpCalled = true;
+
+        return super.onKeyUp(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
+        isOnKeyMultipleCalled = true;
+        onKeyMultipleReturn = super.onKeyMultiple(keyCode, repeatCount, event);
+        keyMultipleEvent = event;
+        return onKeyMultipleReturn;
+    }
+
+    @Override
+    public Bundle onSaveInstanceState() {
+        isOnSaveInstanceStateCalled = true;
+        saveInstanceState = super.onSaveInstanceState();
+        return saveInstanceState;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Bundle savedInstanceState) {
+        isOnRestoreInstanceStateCalled = true;
+        this.savedInstanceState = savedInstanceState;
+
+        super.onRestoreInstanceState(savedInstanceState);
+    }
+
+    @Override
+    public void onWindowAttributesChanged(LayoutParams params) {
+        isOnWindowAttributesChangedCalled = true;
+        super.onWindowAttributesChanged(params);
+    }
+
+    @Override
+    public boolean onCreatePanelMenu(int featureId, Menu menu) {
+        isOnCreatePanelMenuCalled = true;
+        return super.onCreatePanelMenu(featureId, menu);
+    }
+
+    @Override
+    public View onCreatePanelView(int featureId) {
+        isOnCreatePanelViewCalled = true;
+        return super.onCreatePanelView(featureId);
+    }
+
+    @Override
+    public boolean onPreparePanel(int featureId, View view, Menu menu) {
+        isOnPreparePanelCalled = true;
+        return super.onPreparePanel(featureId, view, menu);
+    }
+
+    @Override
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+        isOnMenuItemSelectedCalled = true;
+        return super.onMenuItemSelected(featureId, item);
+    }
+
+    @Override
+    public boolean onMenuOpened(int featureId, Menu menu) {
+        isOnMenuOpenedCalled = true;
+        return super.onMenuOpened(featureId, menu);
+    }
+
+    @Override
+    public void onPanelClosed(int featureId, Menu menu) {
+        isOnPanelClosedCalled = true;
+        super.onPanelClosed(featureId, menu);
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        isOnPrepareOptionsMenuCalled = true;
+        return super.onPrepareOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        menu.add(0, OPTIONS_MENU_ITEM_0, 0, "OptionsMenuItem0");
+        menu.add(0, OPTIONS_MENU_ITEM_1, 0, "OptionsMenuItem1");
+        menu.add(0, OPTIONS_MENU_ITEM_2, 0, "OptionsMenuItem2");
+        menu.add(0, OPTIONS_MENU_ITEM_3, 0, "OptionsMenuItem3");
+        menu.add(0, OPTIONS_MENU_ITEM_4, 0, "OptionsMenuItem4");
+        menu.add(0, OPTIONS_MENU_ITEM_5, 0, "OptionsMenuItem5");
+        menu.add(0, OPTIONS_MENU_ITEM_6, 0, "OptionsMenuItem6");
+        isOnCreateOptionsMenuCalled = true;
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        isOnOptionsItemSelectedCalled = true;
+        switch (item.getItemId()) {
+            case OPTIONS_MENU_ITEM_0:
+            case OPTIONS_MENU_ITEM_1:
+            case OPTIONS_MENU_ITEM_2:
+            case OPTIONS_MENU_ITEM_3:
+            case OPTIONS_MENU_ITEM_4:
+            case OPTIONS_MENU_ITEM_5:
+            case OPTIONS_MENU_ITEM_6:
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
+    @Override
+    public void onOptionsMenuClosed(Menu menu) {
+        isOnOptionsMenuClosedCalled = true;
+        super.onOptionsMenuClosed(menu);
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item) {
+        isOnContextItemSelectedCalled = true;
+        switch (item.getItemId()) {
+            case CONTEXT_MENU_ITEM_0:
+            case CONTEXT_MENU_ITEM_1:
+            case CONTEXT_MENU_ITEM_2:
+                return true;
+            default:
+                return super.onContextItemSelected(item);
+        }
+    }
+
+    @Override
+    public void onContextMenuClosed(Menu menu) {
+        isOnContextMenuClosedCalled = true;
+        super.onContextMenuClosed(menu);
+    }
+
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+        menu.add(0, CONTEXT_MENU_ITEM_0, 0, "ContextMenuItem0");
+        menu.add(0, CONTEXT_MENU_ITEM_1, 0, "ContextMenuItem1");
+        menu.add(0, CONTEXT_MENU_ITEM_2, 0, "ContextMenuItem2");
+        isOnCreateContextMenuCalled = true;
+    }
+
+    @Override
+    public boolean onSearchRequested() {
+        isOnSearchRequestedCalled = true;
+        return super.onSearchRequested();
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        keyEvent = event;
+        dispatchKeyEventResult = super.dispatchKeyEvent(event);
+        return dispatchKeyEventResult;
+    }
+
+    @Override
+    public boolean dispatchTrackballEvent(MotionEvent ev) {
+        trackballEvent = ev;
+        return super.dispatchTrackballEvent(ev);
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        touchEvent = ev;
+        dispatchTouchEventResult = super.dispatchTouchEvent(ev);
+        return dispatchTouchEventResult;
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/TestedActivity.java b/tests/app/app/src/android/app/stubs/TestedActivity.java
new file mode 100644
index 0000000..fb90055
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/TestedActivity.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.util.Log;
+
+public class TestedActivity extends Activity {
+    private static final String TAG = "TestedActivity" ;
+    public TestedActivity() {
+    }
+
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+    }
+
+    protected void onRestoreInstanceState(Bundle state) {
+        super.onRestoreInstanceState(state);
+    }
+
+    protected void onResume() {
+        super.onResume();
+        Looper.myLooper();
+        Looper.myQueue().addIdleHandler(new Idler());
+    }
+
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+    }
+
+    protected void onStop() {
+        super.onStop();
+    }
+
+    private class Idler implements MessageQueue.IdleHandler {
+        public final boolean queueIdle() {
+            Log.i(TAG, "idle");
+            setResult(RESULT_OK);
+            finish();
+            return false;
+        }
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/TestedScreen.java b/tests/app/app/src/android/app/stubs/TestedScreen.java
new file mode 100644
index 0000000..1b707e7
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/TestedScreen.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.os.SystemClock;
+import android.util.Log;
+
+public class TestedScreen extends Activity {
+    public static final String WAIT_BEFORE_FINISH = "TestedScreen.WAIT_BEFORE_FINISH";
+    public static final String DELIVER_RESULT = "TestedScreen.DELIVER_RESULT";
+    public static final String CLEAR_TASK = "TestedScreen.CLEAR_TASK";
+    private static final String TAG = "TestedScreen" ;
+    public TestedScreen() {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        if (LaunchpadActivity.FORWARD_RESULT.equals(getIntent().getAction())) {
+            final Intent intent = new Intent(getIntent());
+            intent.setAction(DELIVER_RESULT);
+            intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+            startActivity(intent);
+            finish();
+        } else if (DELIVER_RESULT.equals(getIntent().getAction())) {
+            setResult(RESULT_OK, new Intent().setAction(LaunchpadActivity.RETURNED_RESULT));
+            finish();
+        } else if (CLEAR_TASK.equals(getIntent().getAction())) {
+            if (!getIntent().getBooleanExtra(ClearTop.WAIT_CLEAR_TASK, false)) {
+                launchClearTask();
+            }
+        }
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle state) {
+        super.onRestoreInstanceState(state);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (CLEAR_TASK.equals(getIntent().getAction())) {
+            if (getIntent().getBooleanExtra(ClearTop.WAIT_CLEAR_TASK, false)) {
+                Looper.myLooper();
+                Looper.myQueue().addIdleHandler(new Idler());
+            }
+        } else {
+            Looper.myLooper();
+            Looper.myQueue().addIdleHandler(new Idler());
+        }
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+    }
+
+    private void launchClearTask() {
+        final Intent intent = new Intent(getIntent()).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+                .setClass(this, ClearTop.class);
+        startActivity(intent);
+    }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if (CLEAR_TASK.equals(getIntent().getAction())) {
+                launchClearTask();
+            } else {
+                setResult(RESULT_OK);
+                finish();
+            }
+        }
+    };
+
+    private class Idler implements MessageQueue.IdleHandler {
+        public final boolean queueIdle() {
+            Log.i(TAG, "idle");
+            if (WAIT_BEFORE_FINISH.equals(getIntent().getAction())) {
+                final Message m = Message.obtain();
+                mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
+            } else if (CLEAR_TASK.equals(getIntent().getAction())) {
+                final Message m = Message.obtain();
+                mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
+            } else {
+                setResult(RESULT_OK);
+                finish();
+            }
+            return false;
+        }
+    }
+}
diff --git a/tests/app/res/values/strings.xml b/tests/app/res/values/strings.xml
deleted file mode 100644
index c167278..0000000
--- a/tests/app/res/values/strings.xml
+++ /dev/null
@@ -1,179 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="permlab_testGranted">Test Granted</string>
-    <string name="permdesc_testGranted">Used for running CTS tests, for testing operations
-        where we have the permission.</string>
-    <string name="permlab_testDynamic">Test Dynamic</string>
-    <string name="permdesc_testDynamic">Used for running CTS tests, for testing adding
-        dynamic permissions.</string>
-    <string name="permlab_testDenied">Test Denied</string>
-    <string name="permdesc_testDenied">Used for running CTS tests, for testing operations
-        where we do not have the permission.</string>
-    <string name="explain">1. click start. \n2. if above image shaked, then press pass button,
-         else press failed button.</string>
-    <string name="text_view_hello">Hello! Text view!</string>
-    <string name="text_view_hello_two_lines">Hello! \nText view!</string>
-    <string name="text_view_simple_hint">This is a hint.</string>
-    <string name="text_view_hint">This is a string for testing hint of textview.</string>
-    <string name="activity_forwarding">App/Forwarding</string>
-    <string name="forwarding">$$$</string>
-    <string name="go">Go</string>
-    <string name="back">Back</string>
-    <string name="forward_target">
-        Press back button and notice we don\'t see the previous activity.
-    </string>
-    <string name="edit_text">testing</string>
-    <string name="text">DialogTest</string>
-    <string name="text_country">Country</string>
-    <string name="text_name">Name</string>
-    <string name="hello_world">Hello, World!</string>
-    <string name="hello_android">Hello, Android!</string>
-    <string name="alert_dialog_username">Name:</string>
-    <string name="alert_dialog_password">Password:</string>
-    <string name="alert_dialog_positive">Positive</string>
-    <string name="alert_dialog_negative">Negative</string>
-    <string name="alert_dialog_neutral">Neutral</string>
-    <string name="notify">Notify </string>
-    <string name="tabs_1">testing</string>
-    <string name="table_layout_first">first</string>
-    <string name="table_layout_second">second</string>
-    <string name="table_layout_third">third</string>
-    <string name="table_layout_long">Very long to make the string out of the screen</string>
-    <string name="chronometer_text">Test Chronometer</string>
-    <string name="am">AM</string>
-    <string name="pm">PM</string>
-    <string name="viewgroup_test">ViewGroup test</string>
-    <string name="viewanimator_test">ViewAnimator test</string>
-    <string name="id_ok">OK</string>
-    <string name="id_cancel">Cancel</string>
-    <string name="context_test_string1">This is %s string.</string>
-    <string name="context_test_string2">This is test string.</string>
-    <string name="animationutils_test_instructions">Choose different animations</string>
-    <string name="animationutils_test_alpha">Alpha animation</string>
-    <string name="animationutils_test_scale">Scale animation</string>
-    <string name="animationutils_test_rotate">Rotate animation</string>
-    <string name="animationutils_test_translate">Translate animation</string>
-    <string name="animationutils_test_set">Animation set</string>
-    <string name="animationutils_test_layout">Layout animation</string>
-    <string name="animationutils_test_gridlayout">Grid layout animation</string>
-    <string name="twolinelistitem_test_text1">text1</string>
-    <string name="twolinelistitem_test_text2">text2</string>
-    <string name="metadata_text">metadata text</string>
-    <string name="horizontal_text_1">horizontal 1</string>
-    <string name="horizontal_text_2">horizontal 2</string>
-    <string name="horizontal_text_3">horizontal 3</string>
-    <string name="vertical_text_1">vertical 1</string>
-    <string name="vertical_text_2">vertical 2</string>
-    <string name="vertical_text_3">vertical 3</string>
-    <string name="reference">here</string>
-    <string name="coerceIntegerToString">100</string>
-    <string name="coerceBooleanToString">true</string>
-    <string name="coerceColorToString">#fff</string>
-    <string name="coerceFloatToString">100.0</string>
-    <string name="coerceDimensionToString">100px</string>
-    <string name="coerceFractionToString">100<xliff:g id="percent">%</xliff:g></string>
-    <string name="formattedStringNone">Format[]</string>
-    <string name="formattedStringOne">Format[<xliff:g id="format">%d</xliff:g>]</string>
-    <string name="formattedStringTwo">Format[<xliff:g id="format">%3$d,%2$s</xliff:g>]</string>
-    <string name="checkboxpref_key">checkboxpref_key</string>
-   <string name="checkboxpref_title">title of preference</string>
-   <string name="checkboxpref_summary">summary of preference</string>
-   <string name="checkboxpref_summary_on">summary on of preference</string>
-   <string name="checkboxpref_summary_off">summary off of preference</string>
-   <string name="checkboxpref_depend">checkboxpref_depend</string>
-   <string name="checkboxpref_depend_title"> depend title of preference</string>
-   <string name="checkboxpref_depend_summary"> depend summary of preference</string>
-   <string name="edittextpref_key">edittextpref_key</string>
-   <string name="edittextpref_default_value">default value of preference</string>
-   <string name="edittextpref_title">title of edit text preference</string>
-   <string name="edittextpref_summary">summary of edit text preference</string>
-   <string name="edittextpref_dialog_title">dialog title of edit text preference</string>
-   <string name="edittextpref_text">text of  edit text preference</string>
-   <string name="listpref_key">listpref_key</string>
-   <string name="listpref_title">title of list preference</string>
-   <string name="listpref_summary">summary of list preference</string>
-   <string name="listpref_dialogtitle">dialog title of list preference</string>
-   <string name="easy">Easy</string>
-   <string name="medium">Medium</string>
-   <string name="hard">Hard</string>
-   <string name="footer_view">Footer view</string>
-   <string name="header_view">Header view</string>
-   <string name="dialogpref_title">title of dialog preference </string>
-   <string name="dialogpref_dialog_title">dialog title of dialog preference </string>
-   <string name="dialogpref_key">dialogpref_key</string>
-   <string name="dialogpref_default_value">default value of dialog preference</string>
-   <string name="dialogpref_summary">summary of dialog preference</string>
-   <string name="dialogpref_message">message of dialog preference</string>
-   <string name="dialogpref_sure">Sure</string>
-   <string name="dialogpref_cancel">Cancel</string>
-   <string name="pref_key">pref_key</string>
-   <string name="pref_title">title of preference</string>
-   <string name="pref_summary">summary of preference</string>
-   <string name="pref_depend_key">pref_depend_key</string>
-   <string name="pref_depend_title"> depend title of preference</string>
-   <string name="pref_depend_summary"> depend summary of preference</string>
-   <string name="android_intent_action_preference">android.intent.action.PREFERENCE</string>
-   <string name="def_pref_key">def_pref_key</string>
-   <string name="def_pref_title">default preference</string>
-   <string name="def_pref_summary">This is default preference of cts</string>
-   <string name="relative_view1">view 1</string>
-   <string name="relative_view2">view 2</string>
-   <string name="relative_view3">view 3</string>
-   <string name="relative_view4">view 4</string>
-   <string name="relative_view5">view 5</string>
-   <string name="relative_view6">view 6</string>
-   <string name="relative_view7">view 7</string>
-   <string name="relative_view8">view 8</string>
-   <string name="relative_view9">view 9</string>
-   <string name="relative_view10">view 10</string>
-   <string name="relative_view11">view 11</string>
-   <string name="relative_view12">view 12</string>
-   <string name="relative_view13">view 13</string>
-   <string name="country">Country:</string>
-   <string name="symbol">Symbol:</string>
-   <string name="country_warning">No such country registered</string>
-   <string name="version_cur">base</string>
-   <string name="version_old">base</string>
-   <string name="version_v3">base</string>
-   <string name="authenticator_label">Android CTS</string>
-   <string name="search_label">Android CTS</string>
-   <string name="tag1">tag 1</string>
-   <string name="tag2">tag 2</string>
-
-   <string name="button">Button</string>
-   <string name="holo_test">Holo Test</string>
-   <string name="holo_generator">Holo Generator</string>
-   <string name="holo_light_test">Holo Light Test</string>
-   <string name="holo_light_generator">Holo Light Generator</string>
-   <string name="reference_image">Reference Image: </string>
-   <string name="generated_image">Generated Image: </string>
-   <string name="themes_prompt">Select a Theme:</string>
-   <string name="sample_text">Sample text goes here. I wanted something creative and whimsical
-but then I just got bored...</string>
-    <string name="long_text">This is a really long string which exceeds the width of the view.
-New devices have a much larger screen which actually enables long strings to be displayed
-with no fading. I have made this string longer to fix this case. If you are correcting this
-text, I would love to see the kind of devices you guys now use! Guys, maybe some devices need longer string!
-I think so, so how about double this string, like copy and paste!
-This is a really long string which exceeds the width of the view.
-New devices have a much larger screen which actually enables long strings to be displayed
-with no fading. I have made this string longer to fix this case. If you are correcting this
-text, I would love to see the kind of devices you guys now use! Guys, maybe some devices need longer string!
-I think so, so how about double this string, like copy and paste! </string>
-    <string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string>
-</resources>
diff --git a/tests/app/res/xml/alias.xml b/tests/app/res/xml/alias.xml
deleted file mode 100644
index 321e536..0000000
--- a/tests/app/res/xml/alias.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright (C) 2008 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.
- */
--->
-
-<alias xmlns:android="http://schemas.android.com/apk/res/android">
-    <intent android:action="android.intent.action.MAIN"
-        android:targetPackage="com.android.cts.app.stub"
-        android:targetClass="android.app.cts.ChildActivity"
-        android:data="http://www.google.com/">
-    </intent>
-</alias>
-
diff --git a/tests/tests/app/src/android/app/backup/cts/BackupAgentHelperTest.java b/tests/app/src/android/app/backup/cts/BackupAgentHelperTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/backup/cts/BackupAgentHelperTest.java
rename to tests/app/src/android/app/backup/cts/BackupAgentHelperTest.java
diff --git a/tests/tests/app/src/android/app/backup/cts/BackupAgentTest.java b/tests/app/src/android/app/backup/cts/BackupAgentTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/backup/cts/BackupAgentTest.java
rename to tests/app/src/android/app/backup/cts/BackupAgentTest.java
diff --git a/tests/app/src/android/app/backup/cts/BackupManagerTest.java b/tests/app/src/android/app/backup/cts/BackupManagerTest.java
new file mode 100644
index 0000000..510e8d1
--- /dev/null
+++ b/tests/app/src/android/app/backup/cts/BackupManagerTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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 android.app.backup.cts;
+
+import android.app.backup.BackupManager;
+import android.app.backup.RestoreObserver;
+import android.test.AndroidTestCase;
+
+public class BackupManagerTest extends AndroidTestCase {
+
+    public void testBackupManager() throws Exception {
+        // Check that these don't crash as if they were called in an app...
+        BackupManager backupManager = new BackupManager(mContext);
+        backupManager.dataChanged();
+        BackupManager.dataChanged("android.app.stubs");
+
+        // Backup isn't expected to work in this test but check for obvious bugs...
+        int result = backupManager.requestRestore(new RestoreObserver() {});
+        assertTrue(result != 0);
+    }
+}
diff --git a/tests/tests/app/src/android/app/backup/cts/FileBackupHelperTest.java b/tests/app/src/android/app/backup/cts/FileBackupHelperTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/backup/cts/FileBackupHelperTest.java
rename to tests/app/src/android/app/backup/cts/FileBackupHelperTest.java
diff --git a/tests/tests/app/src/android/app/backup/cts/SharedPreferencesBackupHelperTest.java b/tests/app/src/android/app/backup/cts/SharedPreferencesBackupHelperTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/backup/cts/SharedPreferencesBackupHelperTest.java
rename to tests/app/src/android/app/backup/cts/SharedPreferencesBackupHelperTest.java
diff --git a/tests/app/src/android/app/cts/ActionBarActivity.java b/tests/app/src/android/app/cts/ActionBarActivity.java
deleted file mode 100644
index dc65cb2..0000000
--- a/tests/app/src/android/app/cts/ActionBarActivity.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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 android.app.cts;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.os.Bundle;
-
-public class ActionBarActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        ActionBar bar = getActionBar();
-        if (bar != null) {
-            bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-        }
-    }
-}
diff --git a/tests/app/src/android/app/cts/ActionBarTest.java b/tests/app/src/android/app/cts/ActionBarTest.java
new file mode 100644
index 0000000..3404b57
--- /dev/null
+++ b/tests/app/src/android/app/cts/ActionBarTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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 android.app.cts;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.ActionBar.TabListener;
+import android.app.FragmentTransaction;
+import android.app.stubs.ActionBarActivity;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+
+public class ActionBarTest extends ActivityInstrumentationTestCase2<ActionBarActivity> {
+
+    private ActionBarActivity mActivity;
+    private ActionBar mBar;
+
+    public ActionBarTest() {
+        super(ActionBarActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mBar = mActivity.getActionBar();
+    }
+
+    @UiThreadTest
+    public void testAddTab() {
+        if (mBar == null) {
+            return;
+        }
+        assertEquals(0, mBar.getTabCount());
+
+        Tab t1 = createTab("Tab 1");
+        mBar.addTab(t1);
+        assertEquals(1, mBar.getTabCount());
+        assertEquals(t1, mBar.getSelectedTab());
+        assertEquals(t1, mBar.getTabAt(0));
+
+        Tab t2 = createTab("Tab 2");
+        mBar.addTab(t2);
+        assertEquals(2, mBar.getTabCount());
+        assertEquals(t1, mBar.getSelectedTab());
+        assertEquals(t2, mBar.getTabAt(1));
+
+        Tab t3 = createTab("Tab 3");
+        mBar.addTab(t3, true);
+        assertEquals(3, mBar.getTabCount());
+        assertEquals(t3, mBar.getSelectedTab());
+        assertEquals(t3, mBar.getTabAt(2));
+
+        Tab t4 = createTab("Tab 2.5");
+        mBar.addTab(t4, 2);
+        assertEquals(4, mBar.getTabCount());
+        assertEquals(t4, mBar.getTabAt(2));
+        assertEquals(t3, mBar.getTabAt(3));
+
+        Tab t5 = createTab("Tab 0.5");
+        mBar.addTab(t5, 0, true);
+        assertEquals(5, mBar.getTabCount());
+        assertEquals(t5, mBar.getSelectedTab());
+        assertEquals(t5, mBar.getTabAt(0));
+        assertEquals(t1, mBar.getTabAt(1));
+        assertEquals(t2, mBar.getTabAt(2));
+        assertEquals(t4, mBar.getTabAt(3));
+        assertEquals(t3, mBar.getTabAt(4));
+    }
+
+    private Tab createTab(String name) {
+        return mBar.newTab().setText("Tab 1").setTabListener(new TestTabListener());
+    }
+
+    static class TestTabListener implements TabListener {
+        @Override
+        public void onTabSelected(Tab tab, FragmentTransaction ft) {
+        }
+
+        @Override
+        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
+        }
+
+        @Override
+        public void onTabReselected(Tab tab, FragmentTransaction ft) {
+        }
+    }
+}
diff --git a/tests/app/src/android/app/cts/ActivityGroupTest.java b/tests/app/src/android/app/cts/ActivityGroupTest.java
new file mode 100644
index 0000000..8b76cb6
--- /dev/null
+++ b/tests/app/src/android/app/cts/ActivityGroupTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.stubs.ActivityTestsBase;
+import android.app.stubs.LaunchpadActivity;
+import android.app.stubs.LaunchpadTabActivity;
+import android.content.ComponentName;
+import android.content.Intent;
+
+public class ActivityGroupTest extends ActivityTestsBase {
+    private Intent mTabIntent;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTabIntent = new Intent(mContext, LaunchpadTabActivity.class);
+        mTabIntent.putExtra("tab", new ComponentName(mContext, LaunchpadActivity.class));
+    }
+
+    public void testTabBasic() throws Exception {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC);
+    }
+
+    public void testTabScreen() throws Exception {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN);
+    }
+
+    public void testTabDialog() throws Exception {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG);
+    }
+}
diff --git a/tests/app/src/android/app/cts/ActivityManagerMemoryClassLaunchActivity.java b/tests/app/src/android/app/cts/ActivityManagerMemoryClassLaunchActivity.java
deleted file mode 100644
index f1f95b8..0000000
--- a/tests/app/src/android/app/cts/ActivityManagerMemoryClassLaunchActivity.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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 android.app.cts;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * {@link Activity} that just launches {@link ActivityManagerMemoryClassTestActivity} and
- * returns the result of that activity.
- */
-public class ActivityManagerMemoryClassLaunchActivity extends Activity {
-
-    public static final String MEMORY_CLASS_EXTRA = "activityMemoryClass";
-
-    private static final int TEST_ACTIVITY_REQUEST_CODE = 1337;
-
-    private final CountDownLatch mLatch = new CountDownLatch(1);
-
-    private int mChildResult = RESULT_CANCELED;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        // Start the activity that runs in a separate process to do the actual testing,
-        // since the test itself cannot start an activity in a separate process. A separate
-        // process is used to avoid including the overhead of the test instrumentation process.
-
-        Intent intent = getIntent();
-        int memoryClass = intent.getIntExtra(MEMORY_CLASS_EXTRA, -1);
-
-        Intent testIntent = new Intent(this, ActivityManagerMemoryClassTestActivity.class);
-        testIntent.putExtra(MEMORY_CLASS_EXTRA, memoryClass);
-        startActivityForResult(testIntent, TEST_ACTIVITY_REQUEST_CODE);
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-        if (requestCode == 1337) {
-            synchronized (this) {
-                mChildResult = resultCode;
-            }
-        } else {
-            throw new IllegalStateException("Request code: " + requestCode);
-        }
-    }
-
-    public int getResult() throws InterruptedException {
-        mLatch.await(5, TimeUnit.SECONDS);
-        synchronized (this) {
-            return mChildResult;
-        }
-    }
-}
diff --git a/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java b/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
new file mode 100644
index 0000000..cb331d1
--- /dev/null
+++ b/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
@@ -0,0 +1,192 @@
+/*
+ * 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 android.app.cts;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.stubs.ActivityManagerMemoryClassLaunchActivity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@link ActivityInstrumentationTestCase2} that tests {@link ActivityManager#getMemoryClass()}
+ * by checking that the memory class matches the proper screen density and by launching an
+ * application that attempts to allocate memory on the heap.
+ */
+public class ActivityManagerMemoryClassTest
+        extends ActivityInstrumentationTestCase2<ActivityManagerMemoryClassLaunchActivity> {
+
+    public ActivityManagerMemoryClassTest() {
+        super(ActivityManagerMemoryClassLaunchActivity.class);
+    }
+
+    public static class ExpectedMemorySizesClass {
+        private static final Map<Integer, Integer> expectedMemorySizeForWatch
+            =  new HashMap<Integer, Integer>();
+        private static final Map<Integer, Integer> expectedMemorySizeForSmallNormalScreen
+            =  new HashMap<Integer, Integer>();
+        private static final Map<Integer, Integer> expectedMemorySizeForLargeScreen
+            =  new HashMap<Integer, Integer>();
+        private static final Map<Integer, Integer> expectedMemorySizeForXLargeScreen
+            =  new HashMap<Integer, Integer>();
+
+        static {
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_LOW, 32);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_MEDIUM, 32);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_TV, 32);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_HIGH, 36);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_280, 36);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XHIGH, 48);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_360, 48);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_400, 56);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_420, 64);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXHIGH, 88);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_560, 112);
+            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXXHIGH, 154);
+        }
+
+        static {
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_LOW, 32);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_MEDIUM, 32);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_TV, 48);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_HIGH, 48);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_280, 48);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XHIGH, 80);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_360, 80);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_400, 96);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_420, 112);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXHIGH, 128);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_560, 192);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 256);
+        }
+
+        static {
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_LOW, 32);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_MEDIUM, 64);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_TV, 80);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_HIGH, 80);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_280, 96);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XHIGH, 128);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_360, 160);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_400, 192);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_420, 228);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XXHIGH, 256);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_560, 384);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 512);
+        }
+
+        static {
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_LOW, 48);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_MEDIUM, 80);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_TV, 96);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_HIGH, 96);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_280, 144);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XHIGH, 192);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_360, 240);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_400, 288);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_420, 336);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXHIGH, 384);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_560, 576);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 768);
+        }
+
+        public static Integer getExpectedMemorySize(
+                int screenSize,
+                int screenDensity,
+                boolean isWatch) {
+
+           if (isWatch) {
+              return expectedMemorySizeForWatch.get(screenDensity);
+           }
+
+           switch (screenSize) {
+                case Configuration.SCREENLAYOUT_SIZE_SMALL:
+                case Configuration.SCREENLAYOUT_SIZE_NORMAL:
+                    return expectedMemorySizeForSmallNormalScreen.get(screenDensity);
+                case Configuration.SCREENLAYOUT_SIZE_LARGE:
+                    return expectedMemorySizeForLargeScreen.get(screenDensity);
+                case Configuration.SCREENLAYOUT_SIZE_XLARGE:
+                    return expectedMemorySizeForXLargeScreen.get(screenDensity);
+                default:
+                    throw new IllegalArgumentException("No memory requirement specified "
+                        + " for screen layout size " + screenSize);
+           }
+        }
+    }
+
+    public void testGetMemoryClass() throws Exception {
+        int memoryClass = getMemoryClass();
+        int screenDensity = getScreenDensity();
+        int screenSize = getScreenSize();
+        assertMemoryForScreenDensity(memoryClass, screenDensity, screenSize);
+
+        runHeapTestApp(memoryClass);
+    }
+
+    private int getMemoryClass() {
+        Context context = getInstrumentation().getTargetContext();
+        ActivityManager activityManager =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        return activityManager.getMemoryClass();
+    }
+
+    private int getScreenDensity() {
+        Context context = getInstrumentation().getTargetContext();
+        WindowManager windowManager =
+                (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        Display display = windowManager.getDefaultDisplay();
+        DisplayMetrics metrics = new DisplayMetrics();
+        display.getMetrics(metrics);
+        return metrics.densityDpi;
+    }
+
+    private int getScreenSize() {
+        Context context = getInstrumentation().getTargetContext();
+        Configuration config = context.getResources().getConfiguration();
+        return config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
+    }
+
+    private void assertMemoryForScreenDensity(int memoryClass, int screenDensity, int screenSize) {
+        Context context = getInstrumentation().getTargetContext();
+        boolean isWatch =
+            context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+        int expectedMinimumMemory =
+            ExpectedMemorySizesClass.getExpectedMemorySize(screenSize, screenDensity, isWatch);
+
+        assertTrue("Expected to have at least " + expectedMinimumMemory
+                + "mb of memory for screen density " + screenDensity,
+                        memoryClass >= expectedMinimumMemory);
+    }
+
+    private void runHeapTestApp(int memoryClass) throws InterruptedException {
+        Intent intent = new Intent();
+        intent.putExtra(ActivityManagerMemoryClassLaunchActivity.MEMORY_CLASS_EXTRA,
+                memoryClass);
+        setActivityIntent(intent);
+        ActivityManagerMemoryClassLaunchActivity activity = getActivity();
+        assertEquals("The test application couldn't allocate memory close to the amount "
+                + " specified by the memory class.", Activity.RESULT_OK, activity.getResult());
+    }
+}
diff --git a/tests/app/src/android/app/cts/ActivityManagerMemoryClassTestActivity.java b/tests/app/src/android/app/cts/ActivityManagerMemoryClassTestActivity.java
deleted file mode 100644
index e717b03..0000000
--- a/tests/app/src/android/app/cts/ActivityManagerMemoryClassTestActivity.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 android.app.cts;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.Log;
-
-/**
- * {@link Activity} that allocates arrays of 256k until reaching 75% of the specified memory class.
- */
-public class ActivityManagerMemoryClassTestActivity extends Activity {
-
-    private static final String TAG = "ActivityManagerMemoryClassTest";
-
-    private static final double FREE_MEMORY_PERCENTAGE = 0.75;
-
-    private static final int ARRAY_BYTES_SIZE = 256 * 1024;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        Intent intent = getIntent();
-        int memoryClass =
-                intent.getIntExtra(ActivityManagerMemoryClassLaunchActivity.MEMORY_CLASS_EXTRA, -1);
-        new AllocateMemoryTask(memoryClass).execute();
-    }
-
-    private class AllocateMemoryTask extends AsyncTask<Void, Void, Void> {
-
-        private final int mMemoryClass;
-
-        AllocateMemoryTask(int memoryClass) {
-            this.mMemoryClass = memoryClass;
-        }
-
-        @Override
-        protected Void doInBackground(Void... params) {
-            int targetMbs = (int) (mMemoryClass * FREE_MEMORY_PERCENTAGE);
-            int numArrays = targetMbs * 1024 * 1024 / ARRAY_BYTES_SIZE;
-            Log.i(TAG, "Memory class: " + mMemoryClass + "mb Target memory: "
-                    + targetMbs + "mb Number of arrays: " + numArrays);
-
-            byte[][] arrays = new byte[numArrays][];
-            for (int i = 0; i < arrays.length; i++) {
-                Log.i(TAG, "Allocating array " + i + " of " + arrays.length
-                        + " (" + (i * ARRAY_BYTES_SIZE / 1024 / 1024) + "mb)");
-                arrays[i] = new byte[ARRAY_BYTES_SIZE];
-            }
-            return null;
-        }
-
-        @Override
-        protected void onPostExecute(Void result) {
-            super.onPostExecute(result);
-            setResult(RESULT_OK);
-            finish();
-        }
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryInfoTest.java b/tests/app/src/android/app/cts/ActivityManagerMemoryInfoTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/cts/ActivityManagerMemoryInfoTest.java
rename to tests/app/src/android/app/cts/ActivityManagerMemoryInfoTest.java
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerProcessErrorStateInfoTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessErrorStateInfoTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/cts/ActivityManagerProcessErrorStateInfoTest.java
rename to tests/app/src/android/app/cts/ActivityManagerProcessErrorStateInfoTest.java
diff --git a/tests/app/src/android/app/cts/ActivityManagerRecentOneActivity.java b/tests/app/src/android/app/cts/ActivityManagerRecentOneActivity.java
deleted file mode 100644
index b3edece..0000000
--- a/tests/app/src/android/app/cts/ActivityManagerRecentOneActivity.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-
-public class ActivityManagerRecentOneActivity extends Activity {
-}
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerRecentTaskInfoTest.java b/tests/app/src/android/app/cts/ActivityManagerRecentTaskInfoTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/cts/ActivityManagerRecentTaskInfoTest.java
rename to tests/app/src/android/app/cts/ActivityManagerRecentTaskInfoTest.java
diff --git a/tests/app/src/android/app/cts/ActivityManagerRecentTwoActivity.java b/tests/app/src/android/app/cts/ActivityManagerRecentTwoActivity.java
deleted file mode 100644
index 97a91cc..0000000
--- a/tests/app/src/android/app/cts/ActivityManagerRecentTwoActivity.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-
-public class ActivityManagerRecentTwoActivity extends Activity {
-}
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerRunningTaskInfoTest.java b/tests/app/src/android/app/cts/ActivityManagerRunningTaskInfoTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/cts/ActivityManagerRunningTaskInfoTest.java
rename to tests/app/src/android/app/cts/ActivityManagerRunningTaskInfoTest.java
diff --git a/tests/app/src/android/app/cts/ActivityManagerStubCrashActivity.java b/tests/app/src/android/app/cts/ActivityManagerStubCrashActivity.java
deleted file mode 100644
index b1c30a8..0000000
--- a/tests/app/src/android/app/cts/ActivityManagerStubCrashActivity.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.TextView;
-
-public class ActivityManagerStubCrashActivity extends Activity {
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        final TextView tv = new TextView(this);
-        tv.setText("Hello, Android but crash");
-        setContentView(tv);
-        die();
-    }
-
-    public void die() {
-        throw new NullPointerException("Expected NPE.");
-    }
-}
-
diff --git a/tests/app/src/android/app/cts/ActivityManagerStubFooActivity.java b/tests/app/src/android/app/cts/ActivityManagerStubFooActivity.java
deleted file mode 100644
index c002ec8..0000000
--- a/tests/app/src/android/app/cts/ActivityManagerStubFooActivity.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.TextView;
-
-public class ActivityManagerStubFooActivity extends Activity {
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        final TextView tv = new TextView(this);
-        tv.setText("Hello, Android");
-        setContentView(tv);
-    }
-}
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
new file mode 100644
index 0000000..c03ad6d
--- /dev/null
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -0,0 +1,530 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.cts;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ActivityManager.RunningServiceInfo;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityOptions;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.app.Instrumentation.ActivityResult;
+import android.app.PendingIntent;
+import android.app.stubs.ActivityManagerRecentOneActivity;
+import android.app.stubs.ActivityManagerRecentTwoActivity;
+import android.app.stubs.MockApplicationActivity;
+import android.app.stubs.MockService;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ConfigurationInfo;
+import android.test.InstrumentationTestCase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ActivityManagerTest extends InstrumentationTestCase {
+    private static final String STUB_PACKAGE_NAME = "android.app.stubs";
+    private static final int WAITFOR_MSEC = 5000;
+    private static final String SERVICE_NAME = "android.app.stubs.MockService";
+    private static final int WAIT_TIME = 2000;
+    // A secondary test activity from another APK.
+    private static final String SIMPLE_PACKAGE_NAME = "com.android.cts.launcherapps.simpleapp";
+    private static final String SIMPLE_ACTIVITY = ".SimpleActivity";
+    private static final String SIMPLE_ACTIVITY_IMMEDIATE_EXIT = ".SimpleActivityImmediateExit";
+    private static final String SIMPLE_ACTIVITY_CHAIN_EXIT = ".SimpleActivityChainExit";
+    // The action sent back by the SIMPLE_APP after a restart.
+    private static final String ACTIVITY_LAUNCHED_ACTION =
+            "com.android.cts.launchertests.LauncherAppsTests.LAUNCHED_ACTION";
+    // The action sent back by the SIMPLE_APP_IMMEDIATE_EXIT when it terminates.
+    private static final String ACTIVITY_EXIT_ACTION =
+            "com.android.cts.launchertests.LauncherAppsTests.EXIT_ACTION";
+    // The action sent back by the SIMPLE_APP_CHAIN_EXIT when the task chain ends. 
+    private static final String ACTIVITY_CHAIN_EXIT_ACTION =
+            "com.android.cts.launchertests.LauncherAppsTests.CHAIN_EXIT_ACTION";
+    // The action sent to identify the time track info.
+    private static final String ACTIVITY_TIME_TRACK_INFO = "com.android.cts.TIME_TRACK_INFO";
+    // Return states of the ActivityReceiverFilter.
+    public static final int RESULT_PASS = 1;
+    public static final int RESULT_FAIL = 2;
+    public static final int RESULT_TIMEOUT = 3;
+
+    private Context mContext;
+    private ActivityManager mActivityManager;
+    private Intent mIntent;
+    private List<Activity> mStartedActivityList;
+    private int mErrorProcessID;
+    private Instrumentation mInstrumentation;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mContext = mInstrumentation.getContext();
+        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        mStartedActivityList = new ArrayList<Activity>();
+        mErrorProcessID = -1;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        if (mIntent != null) {
+            mInstrumentation.getContext().stopService(mIntent);
+        }
+        for (int i = 0; i < mStartedActivityList.size(); i++) {
+            mStartedActivityList.get(i).finish();
+        }
+        if (mErrorProcessID != -1) {
+            android.os.Process.killProcess(mErrorProcessID);
+        }
+    }
+
+    public void testGetRecentTasks() throws Exception {
+        int maxNum = 0;
+        int flags = 0;
+
+        List<RecentTaskInfo> recentTaskList;
+        // Test parameter: maxNum is set to 0
+        recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
+        assertNotNull(recentTaskList);
+        assertTrue(recentTaskList.size() == 0);
+        // Test parameter: maxNum is set to 50
+        maxNum = 50;
+        recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
+        assertNotNull(recentTaskList);
+        // start recent1_activity.
+        startSubActivity(ActivityManagerRecentOneActivity.class);
+        Thread.sleep(WAIT_TIME);
+        // start recent2_activity
+        startSubActivity(ActivityManagerRecentTwoActivity.class);
+        Thread.sleep(WAIT_TIME);
+        /*
+         * assert both recent1_activity and recent2_activity exist in the recent
+         * tasks list. Moreover,the index of the recent2_activity is smaller
+         * than the index of recent1_activity
+         */
+        recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
+        int indexRecentOne = -1;
+        int indexRecentTwo = -1;
+        int i = 0;
+        for (RecentTaskInfo rti : recentTaskList) {
+            if (rti.baseIntent.getComponent().getClassName().equals(
+                    ActivityManagerRecentOneActivity.class.getName())) {
+                indexRecentOne = i;
+            } else if (rti.baseIntent.getComponent().getClassName().equals(
+                    ActivityManagerRecentTwoActivity.class.getName())) {
+                indexRecentTwo = i;
+            }
+            i++;
+        }
+        assertTrue(indexRecentOne != -1 && indexRecentTwo != -1);
+        assertTrue(indexRecentTwo < indexRecentOne);
+
+        try {
+            mActivityManager.getRecentTasks(-1, 0);
+            fail("Should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected exception
+        }
+    }
+
+    public void testGetRecentTasksLimitedToCurrentAPK() throws Exception {
+        int maxNum = 0;
+        int flags = 0;
+
+        // Check the number of tasks at this time.
+        List<RecentTaskInfo>  recentTaskList;
+        recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
+        int numberOfEntriesFirstRun = recentTaskList.size();
+
+        // Start another activity from another APK.
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        ActivityReceiverFilter receiver = new ActivityReceiverFilter(ACTIVITY_LAUNCHED_ACTION);
+        mContext.startActivity(intent);
+
+        // Make sure the activity has really started.
+        assertEquals(RESULT_PASS, receiver.waitForActivity());
+        receiver.close();
+
+        // There shouldn't be any more tasks in this list at this time.
+        recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
+        int numberOfEntriesSecondRun = recentTaskList.size();
+        assertTrue(numberOfEntriesSecondRun == numberOfEntriesFirstRun);
+    }
+
+    // The receiver filter needs to be instantiated with the command to filter for before calling
+    // startActivity.
+    private class ActivityReceiverFilter extends BroadcastReceiver {
+        // The activity we want to filter for.
+        private String mActivityToFilter;
+        private int result = RESULT_TIMEOUT;
+        public long mTimeUsed = 0;
+        private static final int TIMEOUT_IN_MS = 1000;
+
+        // Create the filter with the intent to look for.
+        public ActivityReceiverFilter(String activityToFilter) {
+            mActivityToFilter = activityToFilter;
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(mActivityToFilter);
+            mInstrumentation.getTargetContext().registerReceiver(this, filter);
+        }
+
+        // Turn off the filter.
+        public void close() {
+            mInstrumentation.getTargetContext().unregisterReceiver(this);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(mActivityToFilter)) {
+                synchronized(this) {
+                   result = RESULT_PASS;
+                   if (mActivityToFilter.equals(ACTIVITY_TIME_TRACK_INFO)) {
+                       mTimeUsed = intent.getExtras().getLong(
+                               ActivityOptions.EXTRA_USAGE_TIME_REPORT);
+                   }
+                   notifyAll();
+                }
+            }
+        }
+
+        public int waitForActivity() {
+            synchronized(this) {
+                try {
+                    wait(TIMEOUT_IN_MS);
+                } catch (InterruptedException e) {
+                }
+            }
+            return result;
+        }
+    }
+
+    private final <T extends Activity> void startSubActivity(Class<T> activityClass) {
+        final Instrumentation.ActivityResult result = new ActivityResult(0, new Intent());
+        final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), result, false);
+        mInstrumentation.addMonitor(monitor);
+        launchActivity(STUB_PACKAGE_NAME, activityClass, null);
+        mStartedActivityList.add(monitor.waitForActivity());
+    }
+
+    public void testGetRunningTasks() {
+        // Test illegal parameter
+        List<RunningTaskInfo> runningTaskList;
+        runningTaskList = mActivityManager.getRunningTasks(-1);
+        assertTrue(runningTaskList.size() == 0);
+
+        runningTaskList = mActivityManager.getRunningTasks(0);
+        assertTrue(runningTaskList.size() == 0);
+
+        runningTaskList = mActivityManager.getRunningTasks(20);
+        int taskSize = runningTaskList.size();
+        assertTrue(taskSize >= 0 && taskSize <= 20);
+
+        // start recent1_activity.
+        startSubActivity(ActivityManagerRecentOneActivity.class);
+        // start recent2_activity
+        startSubActivity(ActivityManagerRecentTwoActivity.class);
+
+        /*
+         * assert both recent1_activity and recent2_activity exist in the
+         * running tasks list. Moreover,the index of the recent2_activity is
+         * smaller than the index of recent1_activity
+         */
+        runningTaskList = mActivityManager.getRunningTasks(20);
+        int indexRecentOne = -1;
+        int indexRecentTwo = -1;
+        int i = 0;
+        for (RunningTaskInfo rti : runningTaskList) {
+            if (rti.baseActivity.getClassName().equals(
+                    ActivityManagerRecentOneActivity.class.getName())) {
+                indexRecentOne = i;
+            } else if (rti.baseActivity.getClassName().equals(
+                    ActivityManagerRecentTwoActivity.class.getName())) {
+                indexRecentTwo = i;
+            }
+            i++;
+        }
+        assertTrue(indexRecentOne != -1 && indexRecentTwo != -1);
+        assertTrue(indexRecentTwo < indexRecentOne);
+    }
+
+    public void testGetRunningServices() throws Exception {
+        // Test illegal parameter
+        List<RunningServiceInfo> runningServiceInfo;
+        runningServiceInfo = mActivityManager.getRunningServices(-1);
+        assertTrue(runningServiceInfo.size() == 0);
+
+        runningServiceInfo = mActivityManager.getRunningServices(0);
+        assertTrue(runningServiceInfo.size() == 0);
+
+        runningServiceInfo = mActivityManager.getRunningServices(5);
+        assertTrue(runningServiceInfo.size() >= 0 && runningServiceInfo.size() <= 5);
+
+        Intent intent = new Intent();
+        intent.setClass(mInstrumentation.getTargetContext(), MockService.class);
+        mInstrumentation.getTargetContext().startService(intent);
+        Thread.sleep(WAIT_TIME);
+
+        runningServiceInfo = mActivityManager.getRunningServices(Integer.MAX_VALUE);
+        boolean foundService = false;
+        for (RunningServiceInfo rs : runningServiceInfo) {
+            if (rs.service.getClassName().equals(SERVICE_NAME)) {
+                foundService = true;
+                break;
+            }
+        }
+        assertTrue(foundService);
+        mContext.stopService(intent);
+        Thread.sleep(WAIT_TIME);
+    }
+
+    public void testGetMemoryInfo() {
+        ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();
+        mActivityManager.getMemoryInfo(outInfo);
+        assertTrue(outInfo.lowMemory == (outInfo.availMem <= outInfo.threshold));
+    }
+
+    public void testGetRunningAppProcesses() throws Exception {
+        List<RunningAppProcessInfo> list = mActivityManager.getRunningAppProcesses();
+        assertNotNull(list);
+        final String SYSTEM_PROCESS = "system";
+        boolean hasSystemProcess = false;
+        // The package name is also the default name for the application process
+        final String TEST_PROCESS = STUB_PACKAGE_NAME;
+        boolean hasTestProcess = false;
+        for (RunningAppProcessInfo ra : list) {
+            if (ra.processName.equals(SYSTEM_PROCESS)) {
+                hasSystemProcess = true;
+            } else if (ra.processName.equals(TEST_PROCESS)) {
+                hasTestProcess = true;
+            }
+        }
+        // For security reasons the system process is not exposed.
+        assertTrue(!hasSystemProcess && hasTestProcess);
+
+        for (RunningAppProcessInfo ra : list) {
+            if (ra.processName.equals("android.app.stubs:remote")) {
+                fail("should be no process named android.app.stubs:remote");
+            }
+        }
+        // start a new process
+        mIntent = new Intent("android.app.REMOTESERVICE");
+        mIntent.setPackage("android.app.stubs");
+        mInstrumentation.getTargetContext().startService(mIntent);
+        Thread.sleep(WAITFOR_MSEC);
+
+        List<RunningAppProcessInfo> listNew = mActivityManager.getRunningAppProcesses();
+        assertTrue(list.size() <= listNew.size());
+
+        for (RunningAppProcessInfo ra : listNew) {
+            if (ra.processName.equals("android.app.stubs:remote")) {
+                return;
+            }
+        }
+        fail("android.app.stubs:remote process should be available");
+    }
+
+    public void testGetProcessInErrorState() throws Exception {
+        List<ActivityManager.ProcessErrorStateInfo> errList = null;
+        errList = mActivityManager.getProcessesInErrorState();
+    }
+
+    public void testRestartPackage() {
+    }
+
+    public void testGetDeviceConfigurationInfo() {
+        ConfigurationInfo conInf = mActivityManager.getDeviceConfigurationInfo();
+        assertNotNull(conInf);
+    }
+
+    /**
+     * Simple test for {@link ActivityManager.isUserAMonkey()} - verifies its false.
+     *
+     * TODO: test positive case
+     */
+    public void testIsUserAMonkey() {
+        assertFalse(ActivityManager.isUserAMonkey());
+    }
+
+    /**
+     * Verify that {@link ActivityManager.isRunningInTestHarness()} is false.
+     */
+    public void testIsRunningInTestHarness() {
+        assertFalse("isRunningInTestHarness must be false in production builds",
+                ActivityManager.isRunningInTestHarness());
+    }
+
+    /**
+     * Go back to the home screen since running applications can interfere with application
+     * lifetime tests.
+     */
+    private void launchHome() throws Exception {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(intent);
+        Thread.sleep(WAIT_TIME);
+    }
+
+    /**
+     * Verify that the TimeTrackingAPI works properly when starting and ending an activity.
+     */
+    public void testTimeTrackingAPI_SimpleStartExit() throws Exception {
+        launchHome();
+        // Prepare to start an activity from another APK.
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(SIMPLE_PACKAGE_NAME,
+                SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY_IMMEDIATE_EXIT);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        // Prepare the time receiver action.
+        Context context = mInstrumentation.getTargetContext();
+        ActivityOptions options = ActivityOptions.makeBasic();
+        Intent receiveIntent = new Intent(ACTIVITY_TIME_TRACK_INFO);
+        options.requestUsageTimeReport(PendingIntent.getBroadcast(context,
+                0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT));
+
+        // The application finished tracker.
+        ActivityReceiverFilter appEndReceiver = new ActivityReceiverFilter(ACTIVITY_EXIT_ACTION);
+
+        // The filter for the time event.
+        ActivityReceiverFilter timeReceiver = new ActivityReceiverFilter(ACTIVITY_TIME_TRACK_INFO);
+
+        // Run the activity.
+        mContext.startActivity(intent, options.toBundle());
+
+        // Wait until it finishes and end the reciever then.
+        assertEquals(RESULT_PASS, appEndReceiver.waitForActivity());
+        appEndReceiver.close();
+
+        // At this time the timerReceiver should not fire, even though the activity has shut down,
+        // because we are back to the home screen.
+        assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
+        assertTrue(timeReceiver.mTimeUsed == 0);
+
+        // Issuing now another activity will trigger the timing information release.
+        final Intent dummyIntent = new Intent(context, MockApplicationActivity.class);
+        dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        final Activity activity = mInstrumentation.startActivitySync(dummyIntent);
+
+        // Wait until it finishes and end the reciever then.
+        assertEquals(RESULT_PASS, timeReceiver.waitForActivity());
+        timeReceiver.close();
+        assertTrue(timeReceiver.mTimeUsed != 0);
+    }
+
+    /**
+     * Verify that the TimeTrackingAPI works properly when switching away from the monitored task.
+     */
+    public void testTimeTrackingAPI_SwitchAwayTriggers() throws Exception {
+        launchHome();
+
+        // Prepare to start an activity from another APK.
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        // Prepare the time receiver action.
+        Context context = mInstrumentation.getTargetContext();
+        ActivityOptions options = ActivityOptions.makeBasic();
+        Intent receiveIntent = new Intent(ACTIVITY_TIME_TRACK_INFO);
+        options.requestUsageTimeReport(PendingIntent.getBroadcast(context,
+                0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT));
+
+        // The application started tracker.
+        ActivityReceiverFilter appStartedReceiver = new ActivityReceiverFilter(
+                ACTIVITY_LAUNCHED_ACTION);
+
+        // The filter for the time event.
+        ActivityReceiverFilter timeReceiver = new ActivityReceiverFilter(ACTIVITY_TIME_TRACK_INFO);
+
+        // Run the activity.
+        mContext.startActivity(intent, options.toBundle());
+
+        // Wait until it finishes and end the reciever then.
+        assertEquals(RESULT_PASS, appStartedReceiver.waitForActivity());
+        appStartedReceiver.close();
+
+        // At this time the timerReceiver should not fire since our app is running.
+        assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
+        assertTrue(timeReceiver.mTimeUsed == 0);
+
+        // Starting now another activity will put ours into the back hence releasing the timing.
+        final Intent dummyIntent = new Intent(context, MockApplicationActivity.class);
+        dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        final Activity activity = mInstrumentation.startActivitySync(dummyIntent);
+
+        // Wait until it finishes and end the reciever then.
+        assertEquals(RESULT_PASS, timeReceiver.waitForActivity());
+        timeReceiver.close();
+        assertTrue(timeReceiver.mTimeUsed != 0);
+    }
+
+    /**
+     * Verify that the TimeTrackingAPI works properly when handling an activity chain gets started
+     * and ended.
+     */
+    public void testTimeTrackingAPI_ChainedActivityExit() throws Exception {
+        launchHome();
+        // Prepare to start an activity from another APK.
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(SIMPLE_PACKAGE_NAME,
+                SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY_CHAIN_EXIT);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        // Prepare the time receiver action.
+        Context context = mInstrumentation.getTargetContext();
+        ActivityOptions options = ActivityOptions.makeBasic();
+        Intent receiveIntent = new Intent(ACTIVITY_TIME_TRACK_INFO);
+        options.requestUsageTimeReport(PendingIntent.getBroadcast(context,
+                0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT));
+
+        // The application finished tracker.
+        ActivityReceiverFilter appEndReceiver = new ActivityReceiverFilter(
+                ACTIVITY_CHAIN_EXIT_ACTION);
+
+        // The filter for the time event.
+        ActivityReceiverFilter timeReceiver = new ActivityReceiverFilter(ACTIVITY_TIME_TRACK_INFO);
+
+        // Run the activity.
+        mContext.startActivity(intent, options.toBundle());
+
+        // Wait until it finishes and end the reciever then.
+        assertEquals(RESULT_PASS, appEndReceiver.waitForActivity());
+        appEndReceiver.close();
+
+        // At this time the timerReceiver should not fire, even though the activity has shut down.
+        assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
+        assertTrue(timeReceiver.mTimeUsed == 0);
+
+        // Issue another activity so that the timing information gets released.
+        final Intent dummyIntent = new Intent(context, MockApplicationActivity.class);
+        dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        final Activity activity = mInstrumentation.startActivitySync(dummyIntent);
+
+        // Wait until it finishes and end the reciever then.
+        assertEquals(RESULT_PASS, timeReceiver.waitForActivity());
+        timeReceiver.close();
+        assertTrue(timeReceiver.mTimeUsed != 0);
+    }
+}
diff --git a/tests/tests/app/src/android/app/cts/ActivityManager_RunningAppProcessInfoTest.java b/tests/app/src/android/app/cts/ActivityManager_RunningAppProcessInfoTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/cts/ActivityManager_RunningAppProcessInfoTest.java
rename to tests/app/src/android/app/cts/ActivityManager_RunningAppProcessInfoTest.java
diff --git a/tests/app/src/android/app/cts/ActivityManager_RunningServiceInfoTest.java b/tests/app/src/android/app/cts/ActivityManager_RunningServiceInfoTest.java
new file mode 100644
index 0000000..fa34130
--- /dev/null
+++ b/tests/app/src/android/app/cts/ActivityManager_RunningServiceInfoTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.cts;
+
+import android.app.ActivityManager;
+import android.app.stubs.MockActivity;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+public class ActivityManager_RunningServiceInfoTest extends AndroidTestCase {
+    private ActivityManager.RunningServiceInfo mRunningServiceInfo;
+    private ComponentName mService;
+    private static final String PROCESS = "process";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mRunningServiceInfo = new ActivityManager.RunningServiceInfo();
+        mService = new ComponentName(getContext(), MockActivity.class);
+
+        mRunningServiceInfo.service = mService;
+        mRunningServiceInfo.pid = 1;
+        mRunningServiceInfo.process = PROCESS;
+        mRunningServiceInfo.foreground = true;
+        mRunningServiceInfo.activeSince = 1l;
+        mRunningServiceInfo.started = true;
+        mRunningServiceInfo.clientCount = 2;
+        mRunningServiceInfo.crashCount = 1;
+        mRunningServiceInfo.lastActivityTime = 1l;
+        mRunningServiceInfo.restarting = 1l;
+    }
+
+    public void testConstructor() {
+        new ActivityManager.RunningServiceInfo();
+    }
+
+    public void testDescribeContents() {
+        assertEquals(0, mRunningServiceInfo.describeContents());
+    }
+
+    public void testWriteToParcel() throws Exception {
+
+        Parcel parcel = Parcel.obtain();
+        mRunningServiceInfo.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        ActivityManager.RunningServiceInfo values =
+            ActivityManager.RunningServiceInfo.CREATOR.createFromParcel(parcel);
+        assertEquals(mService, values.service);
+        assertEquals(1, values.pid);
+        assertEquals(PROCESS, values.process);
+        assertTrue(values.foreground);
+        assertEquals(1l, values.activeSince);
+        assertTrue(values.started);
+        assertEquals(2, values.clientCount);
+        assertEquals(1, values.crashCount);
+        assertEquals(1l, values.lastActivityTime);
+        assertEquals(1l, values.restarting);
+    }
+
+    public void testReadFromParcel() throws Exception {
+
+        Parcel parcel = Parcel.obtain();
+        mRunningServiceInfo.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        ActivityManager.RunningServiceInfo values =
+            new ActivityManager.RunningServiceInfo();
+        values.readFromParcel(parcel);
+        assertEquals(mService, values.service);
+        assertEquals(1, values.pid);
+        assertEquals(PROCESS, values.process);
+        assertTrue(values.foreground);
+        assertEquals(1l, values.activeSince);
+        assertTrue(values.started);
+        assertEquals(2, values.clientCount);
+        assertEquals(1, values.crashCount);
+        assertEquals(1l, values.lastActivityTime);
+        assertEquals(1l, values.restarting);
+    }
+
+}
diff --git a/tests/app/src/android/app/cts/ActivityTestsBase.java b/tests/app/src/android/app/cts/ActivityTestsBase.java
deleted file mode 100644
index 426a8b8..0000000
--- a/tests/app/src/android/app/cts/ActivityTestsBase.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.test.AndroidTestCase;
-import android.test.PerformanceTestCase;
-
-public class ActivityTestsBase extends AndroidTestCase implements PerformanceTestCase,
-        LaunchpadActivity.CallingTest {
-    public static final String PERMISSION_GRANTED = "android.app.cts.permission.TEST_GRANTED";
-    public static final String PERMISSION_DENIED = "android.app.cts.permission.TEST_DENIED";
-
-    private static final int TIMEOUT_MS = 60 * 1000;
-
-    protected Intent mIntent;
-
-    private PerformanceTestCase.Intermediates mIntermediates;
-    private String mExpecting;
-
-    // Synchronization of activity result.
-    private boolean mFinished;
-    private int mResultCode = 0;
-    private Intent mData;
-    private RuntimeException mResultStack = null;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mIntent = new Intent(mContext, LaunchpadActivity.class);
-        mIntermediates = null;
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mIntermediates = null;
-        super.tearDown();
-    }
-
-    public boolean isPerformanceOnly() {
-        return false;
-    }
-
-    public void setInternalIterations(int count) {
-    }
-
-    public void startTiming(boolean realTime) {
-        if (mIntermediates != null) {
-            mIntermediates.startTiming(realTime);
-        }
-    }
-
-    public void addIntermediate(String name) {
-        if (mIntermediates != null) {
-            mIntermediates.addIntermediate(name);
-        }
-    }
-
-    public void addIntermediate(String name, long timeInNS) {
-        if (mIntermediates != null) {
-            mIntermediates.addIntermediate(name, timeInNS);
-        }
-    }
-
-    public void finishTiming(boolean realTime) {
-        if (mIntermediates != null) {
-            mIntermediates.finishTiming(realTime);
-        }
-    }
-
-    public void activityFinished(int resultCode, Intent data, RuntimeException where) {
-        finishWithResult(resultCode, data, where);
-    }
-
-    public Intent editIntent() {
-        return mIntent;
-    }
-
-    @Override
-    public Context getContext() {
-        return mContext;
-    }
-
-    public int startPerformance(Intermediates intermediates) {
-        mIntermediates = intermediates;
-        return 1;
-    }
-
-    public void finishGood() {
-        finishWithResult(Activity.RESULT_OK, null);
-    }
-
-    public void finishBad(String error) {
-        finishWithResult(Activity.RESULT_CANCELED, new Intent().setAction(error));
-    }
-
-    public void finishWithResult(int resultCode, Intent data) {
-        final RuntimeException where = new RuntimeException("Original error was here");
-        where.fillInStackTrace();
-        finishWithResult(resultCode, data, where);
-    }
-
-    public void finishWithResult(int resultCode, Intent data, RuntimeException where) {
-        synchronized (this) {
-            mResultCode = resultCode;
-            mData = data;
-            mResultStack = where;
-            mFinished = true;
-            notifyAll();
-        }
-    }
-
-    public int runLaunchpad(String action) {
-        startLaunchpadActivity(action);
-        return waitForResultOrThrow(TIMEOUT_MS);
-    }
-
-    private void startLaunchpadActivity(String action) {
-        LaunchpadActivity.setCallingTest(this);
-
-        synchronized (this) {
-            mIntent.setAction(action);
-            mFinished = false;
-            mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            mContext.startActivity(mIntent);
-        }
-    }
-
-    public int waitForResultOrThrow(int timeoutMs) {
-        return waitForResultOrThrow(timeoutMs, null);
-    }
-
-    public int waitForResultOrThrow(int timeoutMs, String expected) {
-        final int res = waitForResult(timeoutMs, expected);
-
-        if (res == Activity.RESULT_CANCELED) {
-            if (mResultStack != null) {
-                throw new RuntimeException(mData != null ? mData.toString() : "Unable to launch",
-                        mResultStack);
-            } else {
-                throw new RuntimeException(mData != null ? mData.toString() : "Unable to launch");
-            }
-        }
-        return res;
-    }
-
-    public int waitForResult(int timeoutMs, String expected) {
-        mExpecting = expected;
-
-        final long endTime = System.currentTimeMillis() + timeoutMs;
-
-        boolean timeout = false;
-        synchronized (this) {
-            while (!mFinished) {
-                final long delay = endTime - System.currentTimeMillis();
-                if (delay < 0) {
-                    timeout = true;
-                    break;
-                }
-
-                try {
-                    wait(delay);
-                } catch (final java.lang.InterruptedException e) {
-                    // do nothing
-                }
-            }
-        }
-
-        mFinished = false;
-
-        if (timeout) {
-            mResultCode = Activity.RESULT_CANCELED;
-            onTimeout();
-        }
-        return mResultCode;
-    }
-
-
-    public int getResultCode() {
-        return mResultCode;
-    }
-
-    public Intent getResultData() {
-        return mData;
-    }
-
-    public RuntimeException getResultStack() {
-        return mResultStack;
-    }
-
-    public void onTimeout() {
-        final String msg = mExpecting == null ? "Timeout" : "Timeout while expecting " + mExpecting;
-        finishWithResult(Activity.RESULT_CANCELED, new Intent().setAction(msg));
-    }
-}
diff --git a/tests/app/src/android/app/cts/AlarmManagerTest.java b/tests/app/src/android/app/cts/AlarmManagerTest.java
new file mode 100644
index 0000000..fabedd9
--- /dev/null
+++ b/tests/app/src/android/app/cts/AlarmManagerTest.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+
+import android.app.AlarmManager;
+import android.app.AlarmManager.AlarmClockInfo;
+import android.app.PendingIntent;
+import android.app.stubs.MockAlarmReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.cts.util.PollingCheck;
+import android.os.Build;
+import android.os.SystemClock;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.util.Log;
+
+public class AlarmManagerTest extends AndroidTestCase {
+    public static final String MOCKACTION = "android.app.AlarmManagerTest.TEST_ALARMRECEIVER";
+    public static final String MOCKACTION2 = "android.app.AlarmManagerTest.TEST_ALARMRECEIVER2";
+
+    private AlarmManager mAm;
+    private Intent mIntent;
+    private PendingIntent mSender;
+    private Intent mIntent2;
+    private PendingIntent mSender2;
+
+    /*
+     *  The default snooze delay: 5 seconds
+     */
+    private static final long SNOOZE_DELAY = 5 * 1000L;
+    private long mWakeupTime;
+    private MockAlarmReceiver mMockAlarmReceiver;
+    private MockAlarmReceiver mMockAlarmReceiver2;
+
+    private static final int TIME_DELTA = 1000;
+    private static final int TIME_DELAY = 10000;
+    private static final int REPEAT_PERIOD = 60000;
+
+    // Receiver registration/unregistration between tests races with the system process, so
+    // we add a little buffer time here to allow the system to process before we proceed.
+    // This value is in milliseconds.
+    private static final long REGISTER_PAUSE = 250;
+
+    // Constants used for validating exact vs inexact alarm batching immunity.  We run a few
+    // trials of an exact alarm that is placed within an inexact alarm's window of opportunity,
+    // and mandate that the average observed delivery skew between the two be statistically
+    // significant -- i.e. that the two alarms are not being coalesced.  We also place an
+    // additional exact alarm only a short time after the inexact alarm's nominal trigger time.
+    // If exact alarms are allowed to batch with inexact ones this will tend to have no effect,
+    // but in the correct behavior -- inexact alarms not permitted to batch with exact ones --
+    // this additional exact alarm will have the effect of guaranteeing that the inexact alarm
+    // must fire no later than it -- i.e. a considerable time before the significant, later
+    // exact alarm.
+    //
+    // The test essentially amounts to requiring that the inexact MOCKACTION alarm and
+    // the much later exact MOCKACTION2 alarm fire far apart, always; with an implicit
+    // insistence that alarm batches are delivered at the head of their window.
+    private static final long TEST_WINDOW_LENGTH = 5 * 1000L;
+    private static final long TEST_ALARM_FUTURITY = 6 * 1000L;
+    private static final long FAIL_DELTA = 50;
+    private static final long NUM_TRIALS = 5;
+    private static final long MAX_NEAR_DELIVERIES = 2;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mAm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
+        mIntent = new Intent(MOCKACTION)
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mSender = PendingIntent.getBroadcast(mContext, 0, mIntent, 0);
+        mMockAlarmReceiver = new MockAlarmReceiver(mIntent.getAction());
+
+        mIntent2 = new Intent(MOCKACTION2)
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mSender2 = PendingIntent.getBroadcast(mContext, 0, mIntent2, 0);
+        mMockAlarmReceiver2 = new MockAlarmReceiver(mIntent2.getAction());
+
+        IntentFilter filter = new IntentFilter(mIntent.getAction());
+        mContext.registerReceiver(mMockAlarmReceiver, filter);
+
+        IntentFilter filter2 = new IntentFilter(mIntent2.getAction());
+        mContext.registerReceiver(mMockAlarmReceiver2, filter2);
+
+        Thread.sleep(REGISTER_PAUSE);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mContext.unregisterReceiver(mMockAlarmReceiver);
+        mContext.unregisterReceiver(mMockAlarmReceiver2);
+
+        Thread.sleep(REGISTER_PAUSE);
+    }
+
+    public void testSetTypes() throws Exception {
+        // TODO: try to find a way to make device sleep then test whether
+        // AlarmManager perform the expected way
+
+        // test parameter type is RTC_WAKEUP
+        mMockAlarmReceiver.setAlarmedFalse();
+        mWakeupTime = System.currentTimeMillis() + SNOOZE_DELAY;
+        mAm.setExact(AlarmManager.RTC_WAKEUP, mWakeupTime, mSender);
+        new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
+            @Override
+            protected boolean check() {
+                return mMockAlarmReceiver.alarmed;
+            }
+        }.run();
+        assertEquals(mMockAlarmReceiver.rtcTime, mWakeupTime, TIME_DELTA);
+
+        // test parameter type is RTC
+        mMockAlarmReceiver.setAlarmedFalse();
+        mWakeupTime = System.currentTimeMillis() + SNOOZE_DELAY;
+        mAm.setExact(AlarmManager.RTC, mWakeupTime, mSender);
+        new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
+            @Override
+            protected boolean check() {
+                return mMockAlarmReceiver.alarmed;
+            }
+        }.run();
+        assertEquals(mMockAlarmReceiver.rtcTime, mWakeupTime, TIME_DELTA);
+
+        // test parameter type is ELAPSED_REALTIME
+        mMockAlarmReceiver.setAlarmedFalse();
+        mWakeupTime = SystemClock.elapsedRealtime() + SNOOZE_DELAY;
+        mAm.setExact(AlarmManager.ELAPSED_REALTIME, mWakeupTime, mSender);
+        new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
+            @Override
+            protected boolean check() {
+                return mMockAlarmReceiver.alarmed;
+            }
+        }.run();
+        assertEquals(mMockAlarmReceiver.elapsedTime, mWakeupTime, TIME_DELTA);
+
+        // test parameter type is ELAPSED_REALTIME_WAKEUP
+        mMockAlarmReceiver.setAlarmedFalse();
+        mWakeupTime = SystemClock.elapsedRealtime() + SNOOZE_DELAY;
+        mAm.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, mWakeupTime, mSender);
+        new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
+            @Override
+            protected boolean check() {
+                return mMockAlarmReceiver.alarmed;
+            }
+        }.run();
+        assertEquals(mMockAlarmReceiver.elapsedTime, mWakeupTime, TIME_DELTA);
+    }
+
+    public void testAlarmTriggersImmediatelyIfSetTimeIsNegative() throws Exception {
+        // An alarm with a negative wakeup time should be triggered immediately.
+        // This exercises a workaround for a limitation of the /dev/alarm driver
+        // that would instead cause such alarms to never be triggered.
+        mMockAlarmReceiver.setAlarmedFalse();
+        mWakeupTime = -1000;
+        mAm.set(AlarmManager.RTC, mWakeupTime, mSender);
+        new PollingCheck(TIME_DELAY) {
+            @Override
+            protected boolean check() {
+                return mMockAlarmReceiver.alarmed;
+            }
+        }.run();
+    }
+
+    public void testExactAlarmBatching() throws Exception {
+        int deliveriesTogether = 0;
+        for (int i = 0; i < NUM_TRIALS; i++) {
+            final long now = System.currentTimeMillis();
+            final long windowStart = now + TEST_ALARM_FUTURITY;
+            final long exactStart = windowStart + TEST_WINDOW_LENGTH - 1;
+
+            mMockAlarmReceiver.setAlarmedFalse();
+            mMockAlarmReceiver2.setAlarmedFalse();
+            mAm.setWindow(AlarmManager.RTC_WAKEUP, windowStart, TEST_WINDOW_LENGTH, mSender);
+            mAm.setExact(AlarmManager.RTC_WAKEUP, exactStart, mSender2);
+
+            // Wait until a half-second beyond its target window, just to provide a
+            // little safety slop.
+            new PollingCheck(TEST_WINDOW_LENGTH + (windowStart - now) + 500) {
+                @Override
+                protected boolean check() {
+                    return mMockAlarmReceiver.alarmed;
+                }
+            }.run();
+
+            // Now wait until 1 sec beyond the expected exact alarm fire time, or for at
+            // least one second if we're already past the nominal exact alarm fire time
+            long timeToExact = Math.max(exactStart - System.currentTimeMillis() + 1000, 1000);
+            new PollingCheck(timeToExact) {
+                @Override
+                protected boolean check() {
+                    return mMockAlarmReceiver2.alarmed;
+                }
+            }.run();
+
+            // Success when we observe that the exact and windowed alarm are not being often
+            // delivered close together -- that is, when we can be confident that they are not
+            // being coalesced.
+            final long delta = Math.abs(mMockAlarmReceiver2.rtcTime - mMockAlarmReceiver.rtcTime);
+            Log.i("TEST", "[" + i + "]  delta = " + delta);
+            if (delta < FAIL_DELTA) {
+                deliveriesTogether++;
+                assertTrue("Exact alarms appear to be coalescing with inexact alarms",
+                        deliveriesTogether <= MAX_NEAR_DELIVERIES);
+            }
+        }
+    }
+
+    public void testSetRepeating() throws Exception {
+        mMockAlarmReceiver.setAlarmedFalse();
+        mWakeupTime = System.currentTimeMillis() + TEST_ALARM_FUTURITY;
+        mAm.setRepeating(AlarmManager.RTC_WAKEUP, mWakeupTime, REPEAT_PERIOD, mSender);
+
+        // wait beyond the initial alarm's possible delivery window to verify that it fires the first time
+        new PollingCheck(TEST_ALARM_FUTURITY + REPEAT_PERIOD) {
+            @Override
+            protected boolean check() {
+                return mMockAlarmReceiver.alarmed;
+            }
+        }.run();
+        assertTrue(mMockAlarmReceiver.alarmed);
+
+        // Now reset the receiver and wait for the intended repeat alarm to fire as expected
+        mMockAlarmReceiver.setAlarmedFalse();
+        new PollingCheck(REPEAT_PERIOD*2) {
+            @Override
+            protected boolean check() {
+                return mMockAlarmReceiver.alarmed;
+            }
+        }.run();
+        assertTrue(mMockAlarmReceiver.alarmed);
+
+        mAm.cancel(mSender);
+    }
+
+    public void testCancel() throws Exception {
+        mMockAlarmReceiver.setAlarmedFalse();
+        mMockAlarmReceiver2.setAlarmedFalse();
+
+        // set two alarms
+        final long when1 = System.currentTimeMillis() + TEST_ALARM_FUTURITY;
+        mAm.setExact(AlarmManager.RTC_WAKEUP, when1, mSender);
+        final long when2 = when1 + TIME_DELTA; // will fire after when1's target time
+        mAm.setExact(AlarmManager.RTC_WAKEUP, when2, mSender2);
+
+        // cancel the earlier one
+        mAm.cancel(mSender);
+
+        // and verify that only the later one fired
+        new PollingCheck(TIME_DELAY) {
+            @Override
+            protected boolean check() {
+                return mMockAlarmReceiver2.alarmed;
+            }
+        }.run();
+
+        assertFalse(mMockAlarmReceiver.alarmed);
+        assertTrue(mMockAlarmReceiver2.alarmed);
+    }
+
+    public void testSetInexactRepeating() throws Exception {
+        mAm.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
+                AlarmManager.INTERVAL_FIFTEEN_MINUTES, mSender);
+        SystemClock.setCurrentTimeMillis(System.currentTimeMillis()
+                + AlarmManager.INTERVAL_FIFTEEN_MINUTES);
+        // currently there is no way to write Android system clock. When try to
+        // write the system time, there will be log as
+        // " Unable to open alarm driver: Permission denied". But still fail
+        // after tried many permission.
+    }
+
+    public void testSetAlarmClock() throws Exception {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            mMockAlarmReceiver.setAlarmedFalse();
+            mMockAlarmReceiver2.setAlarmedFalse();
+
+            // Set first alarm clock.
+            final long wakeupTimeFirst = System.currentTimeMillis()
+                    + 2 * TEST_ALARM_FUTURITY;
+            mAm.setAlarmClock(new AlarmClockInfo(wakeupTimeFirst, null), mSender);
+
+            // Verify getNextAlarmClock returns first alarm clock.
+            AlarmClockInfo nextAlarmClock = mAm.getNextAlarmClock();
+            assertEquals(wakeupTimeFirst, nextAlarmClock.getTriggerTime());
+            assertNull(nextAlarmClock.getShowIntent());
+
+            // Set second alarm clock, earlier than first.
+            final long wakeupTimeSecond = System.currentTimeMillis()
+                    + TEST_ALARM_FUTURITY;
+            PendingIntent showIntentSecond = PendingIntent.getBroadcast(getContext(), 0,
+                    new Intent(getContext(), AlarmManagerTest.class).setAction("SHOW_INTENT"), 0);
+            mAm.setAlarmClock(new AlarmClockInfo(wakeupTimeSecond, showIntentSecond),
+                    mSender2);
+
+            // Verify getNextAlarmClock returns second alarm clock now.
+            nextAlarmClock = mAm.getNextAlarmClock();
+            assertEquals(wakeupTimeSecond, nextAlarmClock.getTriggerTime());
+            assertEquals(showIntentSecond, nextAlarmClock.getShowIntent());
+
+            // Cancel second alarm.
+            mAm.cancel(mSender2);
+
+            // Verify getNextAlarmClock returns first alarm clock again.
+            nextAlarmClock = mAm.getNextAlarmClock();
+            assertEquals(wakeupTimeFirst, nextAlarmClock.getTriggerTime());
+            assertNull(nextAlarmClock.getShowIntent());
+
+            // Wait for first alarm to trigger.
+            assertFalse(mMockAlarmReceiver.alarmed);
+            new PollingCheck(2 * TEST_ALARM_FUTURITY + TIME_DELAY) {
+                @Override
+                protected boolean check() {
+                    return mMockAlarmReceiver.alarmed;
+                }
+            }.run();
+
+            // Verify first alarm fired at the right time.
+            assertEquals(mMockAlarmReceiver.rtcTime, wakeupTimeFirst, TIME_DELTA);
+
+            // Verify second alarm didn't fire.
+            assertFalse(mMockAlarmReceiver2.alarmed);
+
+            // Verify the next alarm is not returning neither the first nor the second alarm.
+            nextAlarmClock = mAm.getNextAlarmClock();
+            MoreAsserts.assertNotEqual(wakeupTimeFirst, nextAlarmClock != null
+                    ? nextAlarmClock.getTriggerTime()
+                    : null);
+            MoreAsserts.assertNotEqual(wakeupTimeSecond, nextAlarmClock != null
+                    ? nextAlarmClock.getTriggerTime()
+                    : null);
+        }
+    }
+}
diff --git a/tests/app/src/android/app/cts/AlertDialogTest.java b/tests/app/src/android/app/cts/AlertDialogTest.java
new file mode 100644
index 0000000..1fe8de4
--- /dev/null
+++ b/tests/app/src/android/app/cts/AlertDialogTest.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.AlertDialog;
+import android.app.Instrumentation;
+import android.app.stubs.DialogStubActivity;
+import android.content.DialogInterface;
+import android.cts.util.PollingCheck;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.widget.Button;
+
+import android.app.stubs.R;
+/*
+ * Test AlertDialog
+ */
+public class AlertDialogTest extends ActivityInstrumentationTestCase2<DialogStubActivity> {
+    private static final String ALERTDIALOG_CUSTOM_TITLE = "Hello, World!";
+
+    private Instrumentation mInstrumentation;
+    private DialogStubActivity mActivity;
+    private Button mPositiveButton;
+    private Button mNegativeButton;
+    private Button mNeutralButton;
+
+    public AlertDialogTest() {
+        super("android.app.stubs", DialogStubActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+    }
+
+    protected void startDialogActivity(int dialogNumber) {
+        mActivity = DialogStubActivity.startDialogActivity(this, dialogNumber);
+        new PollingCheck() {
+            @Override
+            protected boolean check() {
+                return mActivity.getDialog().isShowing();
+            }
+        }.run();
+    }
+
+    public void testAlertDialog() throws Throwable {
+        doTestAlertDialog(DialogStubActivity.TEST_ALERTDIALOG);
+    }
+
+    private void doTestAlertDialog(int index) throws Throwable {
+        startDialogActivity(index);
+        assertTrue(mActivity.getDialog().isShowing());
+
+        mPositiveButton = ((AlertDialog) (mActivity.getDialog())).getButton(
+                DialogInterface.BUTTON_POSITIVE);
+        assertNotNull(mPositiveButton);
+        assertEquals(mActivity.getString(R.string.alert_dialog_positive),
+                mPositiveButton.getText());
+        mNeutralButton = ((AlertDialog) (mActivity.getDialog())).getButton(
+                DialogInterface.BUTTON_NEUTRAL);
+        assertNotNull(mNeutralButton);
+        assertEquals(mActivity.getString(R.string.alert_dialog_neutral),
+                mNeutralButton.getText());
+        mNegativeButton = ((AlertDialog) (mActivity.getDialog())).getButton(
+                DialogInterface.BUTTON_NEGATIVE);
+        assertNotNull(mNegativeButton);
+        assertEquals(mActivity.getString(R.string.alert_dialog_negative),
+                mNegativeButton.getText());
+
+        assertFalse(mActivity.isPositiveButtonClicked);
+        performClick(mPositiveButton);
+        assertTrue(mActivity.isPositiveButtonClicked);
+
+        assertFalse(mActivity.isNegativeButtonClicked);
+        performClick(mNegativeButton);
+        assertTrue(mActivity.isNegativeButtonClicked);
+
+        assertFalse(mActivity.isNeutralButtonClicked);
+        performClick(mNeutralButton);
+        assertTrue(mActivity.isNeutralButtonClicked);
+    }
+
+    public void testAlertDialogDeprecatedAPI() throws Throwable {
+        doTestAlertDialog(DialogStubActivity.TEST_ALERTDIALOG_DEPRECATED);
+    }
+
+    public void testAlertDialogDeprecatedAPIWithMessage() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ALERTDIALOG_DEPRECATED_WITH_MESSAGE);
+        assertTrue(mActivity.getDialog().isShowing());
+
+        mPositiveButton = ((AlertDialog) (mActivity.getDialog())).getButton(
+                DialogInterface.BUTTON_POSITIVE);
+        assertNotNull(mPositiveButton);
+        assertEquals(mActivity.getString(R.string.alert_dialog_positive),
+                mPositiveButton.getText());
+        mNegativeButton = ((AlertDialog) (mActivity.getDialog())).getButton(
+                DialogInterface.BUTTON_NEGATIVE);
+        assertNotNull(mNegativeButton);
+        assertEquals(mActivity.getString(R.string.alert_dialog_negative),
+                mNegativeButton.getText());
+        mNeutralButton = ((AlertDialog) (mActivity.getDialog())).getButton(
+                DialogInterface.BUTTON_NEUTRAL);
+        assertNotNull(mNeutralButton);
+        assertEquals(mActivity.getString(R.string.alert_dialog_neutral),
+                mNeutralButton.getText());
+
+        DialogStubActivity.buttonIndex = 0;
+        performClick(mPositiveButton);
+        assertEquals(DialogInterface.BUTTON_POSITIVE, DialogStubActivity.buttonIndex);
+
+        DialogStubActivity.buttonIndex = 0;
+        performClick(mNeutralButton);
+        assertEquals(DialogInterface.BUTTON_NEUTRAL, DialogStubActivity.buttonIndex);
+
+        DialogStubActivity.buttonIndex = 0;
+        performClick(mNegativeButton);
+        assertEquals(DialogInterface.BUTTON_NEGATIVE, DialogStubActivity.buttonIndex);
+    }
+
+    private void performClick(final Button button) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                button.performClick();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testCustomAlertDialog() {
+        startDialogActivity(DialogStubActivity.TEST_CUSTOM_ALERTDIALOG);
+        assertTrue(mActivity.getDialog().isShowing());
+    }
+
+    public void testCustomAlertDialogView() {
+        startDialogActivity(DialogStubActivity.TEST_CUSTOM_ALERTDIALOG_VIEW);
+        assertTrue(mActivity.getDialog().isShowing());
+    }
+
+
+    public void testCallback() {
+        startDialogActivity(DialogStubActivity.TEST_ALERTDIALOG_CALLBACK);
+        assertTrue(mActivity.onCreateCalled);
+
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
+        assertTrue(mActivity.onKeyDownCalled);
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
+        assertTrue(mActivity.onKeyUpCalled);
+    }
+
+    public void testAlertDialogTheme() throws Exception {
+        startDialogActivity(DialogStubActivity.TEST_ALERTDIALOG_THEME);
+        assertTrue(mActivity.getDialog().isShowing());
+    }
+
+    public void testAlertDialogCancelable() throws Exception {
+        startDialogActivity(DialogStubActivity.TEST_ALERTDIALOG_CANCELABLE);
+        assertTrue(mActivity.getDialog().isShowing());
+        assertFalse(mActivity.onCancelCalled);
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.onCancelCalled);
+    }
+
+    public void testAlertDialogNotCancelable() throws Exception {
+        startDialogActivity(DialogStubActivity.TEST_ALERTDIALOG_NOT_CANCELABLE);
+        assertTrue(mActivity.getDialog().isShowing());
+        assertFalse(mActivity.onCancelCalled);
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        assertFalse(mActivity.onCancelCalled);
+    }
+}
diff --git a/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java b/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
new file mode 100644
index 0000000..1a60225
--- /dev/null
+++ b/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Instrumentation;
+import android.app.stubs.DialogStubActivity;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.DialogInterface.OnClickListener;
+import android.content.DialogInterface.OnKeyListener;
+import android.content.DialogInterface.OnMultiChoiceClickListener;
+import android.cts.util.PollingCheck;
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import android.graphics.drawable.Drawable;
+import android.provider.Contacts.People;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import android.app.stubs.R;
+
+import java.util.ArrayList;
+
+public class AlertDialog_BuilderTest extends ActivityInstrumentationTestCase2<DialogStubActivity> {
+    private Builder mBuilder;
+    private Context mContext;
+    private Instrumentation mInstrumentation;
+    private final CharSequence mTitle = "title";
+    private Drawable mDrawable;
+    private AlertDialog mDialog;
+    private Button mButton;
+    private boolean mResult;
+    private boolean mItemSelected;
+    private CharSequence mSelectedItem;
+    private final String[] mPROJECTION = new String[] {
+            People._ID, People.NAME
+    };
+
+    private View mView;
+    private ListView mListView;
+    private ArrayList<Integer> mSelectedItems;
+    private FrameLayout mFrameLayout;
+
+    private OnClickListener mOnClickListener = new OnClickListener() {
+        public void onClick(DialogInterface dialog, int which) {
+            mResult = true;
+        }
+    };
+
+    private OnCancelListener mOnCancelListener = new OnCancelListener() {
+        public void onCancel(DialogInterface dialog) {
+            mResult = true;
+        }
+    };
+
+    private OnKeyListener mOnKeyListener = new OnKeyListener() {
+        public boolean onKey(DialogInterface dialog, int key, KeyEvent envnt) {
+            mResult = true;
+            return true;
+        }
+    };
+
+    private OnItemSelectedListener mOnItemSelectedListener = new OnItemSelectedListener() {
+        public void onItemSelected(AdapterView parent, View v, int position, long id) {
+            mItemSelected = true;
+        }
+
+        public void onNothingSelected(AdapterView parent) {
+        }
+
+    };
+
+    private OnMultiChoiceClickListener mOnMultiChoiceClickListener =
+        new OnMultiChoiceClickListener() {
+        public void onClick(DialogInterface dialog, int which, boolean isChecked) {
+            mSelectedItems.add(which);
+            mResult = true;
+        }
+    };
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mBuilder = null;
+        mInstrumentation = getInstrumentation();
+        mContext = getActivity();
+        final Activity activity = getActivity();
+        new PollingCheck() {
+            @Override
+            protected boolean check() {
+                return activity.hasWindowFocus();
+            }
+        }.run();
+        mButton = null;
+        mView = null;
+        mListView = null;
+        mDialog = null;
+        mItemSelected = false;
+        mSelectedItem = null;
+        mSelectedItems = new ArrayList<Integer>();
+    }
+
+    public AlertDialog_BuilderTest() {
+        super("android.app.stubs", DialogStubActivity.class);
+    }
+
+    public void testConstructor() {
+        new AlertDialog.Builder(mContext);
+    }
+
+    public void testSetIconWithParamInt() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mDrawable = mContext.getResources().getDrawable(android.R.drawable.btn_default);
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setIcon(android.R.drawable.btn_default);
+                mDialog = mBuilder.show();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testSetIconWithParamDrawable() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mDrawable = mContext.getResources().getDrawable(android.R.drawable.btn_default);
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setIcon(mDrawable);
+                mDialog = mBuilder.show();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testSetPositiveButtonWithParamInt() throws Throwable {
+       runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setPositiveButton(android.R.string.yes, mOnClickListener);
+                mDialog = mBuilder.show();
+                mButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+                mButton.performClick();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(mContext.getText(android.R.string.yes), mButton.getText());
+        assertTrue(mResult);
+    }
+
+    public void testSetPositiveButtonWithParamCharSequence() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setPositiveButton(android.R.string.yes, mOnClickListener);
+                mDialog = mBuilder.show();
+                mButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+                mButton.performClick();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(mContext.getText(android.R.string.yes), mButton.getText());
+        assertTrue(mResult);
+    }
+
+    public void testSetNegativeButtonWithParamCharSequence() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setNegativeButton(mTitle, mOnClickListener);
+                mDialog = mBuilder.show();
+                mButton = mDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+                mButton.performClick();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(mTitle, mButton.getText());
+        assertTrue(mResult);
+    }
+
+    public void testSetNegativeButtonWithParamInt() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setNegativeButton(R.string.notify, mOnClickListener);
+                mDialog = mBuilder.show();
+                mButton = mDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+                mButton.performClick();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(mContext.getText(R.string.notify), mButton.getText());
+        assertTrue(mResult);
+    }
+
+    public void testSetNeutralButtonWithParamInt() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setNeutralButton(R.string.notify, mOnClickListener);
+                mDialog = mBuilder.show();
+                mButton = mDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+                mButton.performClick();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(mContext.getText(R.string.notify), mButton.getText());
+        assertTrue(mResult);
+    }
+
+    public void testSetNeutralButtonWithParamCharSequence() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setNeutralButton(mTitle, mOnClickListener);
+                mDialog = mBuilder.show();
+                mButton = mDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+                mButton.performClick();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(mTitle, mButton.getText());
+        assertTrue(mResult);
+    }
+
+    private void testCancelable(final boolean cancelable) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setCancelable(cancelable);
+                mDialog = mBuilder.show();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        new PollingCheck() {
+            @Override
+            protected boolean check() {
+                return mDialog.isShowing();
+            }
+        }.run();
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        mInstrumentation.waitForIdleSync();
+        new PollingCheck() {
+            @Override
+            protected boolean check() {
+                boolean showing = mDialog.isShowing();
+                if (cancelable) {
+                    // if the dialog is cancelable, then pressing back
+                    // should cancel it. Thus it should not be showing
+                    return !showing;
+                } else {
+                    // if the dialog is not cancelable, pressing back
+                    // should so nothing and it should still be showing
+                    return showing;
+                }
+            }
+        }.run();
+    }
+
+    public void testSetCancelable() throws Throwable {
+        testCancelable(true);
+    }
+
+    public void testDisableCancelable() throws Throwable {
+        testCancelable(false);
+    }
+
+    public void testSetOnCancelListener() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setOnCancelListener(mOnCancelListener);
+                mDialog = mBuilder.show();
+                mDialog.cancel();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mResult);
+    }
+
+    public void testSetOnKeyListener() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setOnKeyListener(mOnKeyListener);
+                mDialog = mBuilder.show();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        sendKeys(KeyEvent.ACTION_DOWN, KeyEvent.ACTION_DOWN);
+        assertTrue(mResult);
+    }
+
+    public void testSetItemsWithParamInt() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setItems(R.array.difficultyLevel, mOnClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        final CharSequence[] levels = mContext.getResources().getTextArray(
+                R.array.difficultyLevel);
+        assertEquals(levels[0], mListView.getItemAtPosition(0));
+    }
+
+    public void testSetItemsWithParamCharSequence() throws Throwable {
+        final CharSequence[] expect = mContext.getResources().getTextArray(
+                R.array.difficultyLevel);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setItems(expect, mOnClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(expect[0], mListView.getItemAtPosition(0));
+    }
+
+    public void testSetAdapter() throws Throwable {
+        final ListAdapter adapter = new AdapterTest();
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setAdapter(adapter, mOnClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(adapter, mListView.getAdapter());
+    }
+
+    public void testSetCursor() throws Throwable {
+        preparePeople();
+        final Cursor c = mContext.getContentResolver().query(People.CONTENT_URI, mPROJECTION, null,
+                null, null);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setCursor(c, mOnClickListener, People.NAME);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+                mListView.performItemClick(null, 0, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final CursorWrapper selected = (CursorWrapper)mListView.getSelectedItem();
+        assertEquals(c.getString(1), selected.getString(1));
+        assertTrue(mResult);
+    }
+
+    public void testSetMultiChoiceItemsWithParamInt() throws Throwable {
+
+        final CharSequence[] items = mContext.getResources().getTextArray(
+                R.array.difficultyLevel);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setMultiChoiceItems(R.array.difficultyLevel, null,
+                        mOnMultiChoiceClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+                mSelectedItem = (CharSequence)mListView.getSelectedItem();
+                mListView.performItemClick(null, 0, 0);
+                mListView.performItemClick(null, 1, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(items[0], mSelectedItem);
+        assertEquals(2, mSelectedItems.size());
+        assertEquals(items[0], mListView.getItemAtPosition(0));
+        assertTrue(mResult);
+    }
+
+    public void testSetMultiChoiceItemsWithParamCharSequence() throws Throwable {
+        final CharSequence[] items = mContext.getResources().getTextArray(
+                R.array.difficultyLevel);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setMultiChoiceItems(items, null, mOnMultiChoiceClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+                mSelectedItem = (CharSequence)mListView.getSelectedItem();
+                mListView.performItemClick(null, 0, 0);
+                mListView.performItemClick(null, 1, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(items[0], mSelectedItem);
+        assertEquals(2, mSelectedItems.size());
+        assertEquals(items[0], mListView.getItemAtPosition(0));
+        assertTrue(mResult);
+    }
+
+    public void testSetMultiChoiceItemsWithParamCursor() throws Throwable {
+        preparePeople();
+        final Cursor c = mContext.getContentResolver().query(People.CONTENT_URI, mPROJECTION, null,
+                null, null);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setMultiChoiceItems(c, People.NAME, People.NAME,
+                        mOnMultiChoiceClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+                mListView.performItemClick(null, 0, 0);
+                mListView.performItemClick(null, 1, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final CursorWrapper selected = (CursorWrapper)mListView.getSelectedItem();
+        assertEquals(c.getString(1), selected.getString(1));
+        assertEquals(2, mSelectedItems.size());
+        assertTrue(mResult);
+    }
+
+    public void testSetSingleChoiceItemsWithParamInt() throws Throwable {
+        final CharSequence[] items = mContext.getResources().getTextArray(
+                R.array.difficultyLevel);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setSingleChoiceItems(R.array.difficultyLevel, 0,
+                        mOnClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+                mSelectedItem = (CharSequence)mListView.getSelectedItem();
+                mListView.performItemClick(null, 0, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(items[0], mSelectedItem);
+        assertEquals(items[0], mListView.getItemAtPosition(0));
+        assertTrue(mResult);
+    }
+
+    private void preparePeople() {
+        final ContentResolver mResolver = mContext.getContentResolver();
+        mResolver.delete(People.CONTENT_URI, null, null);
+        final ContentValues valuse = new ContentValues();
+        valuse.put(People._ID, "1");
+        valuse.put(People.NAME, "name");
+        mResolver.insert(People.CONTENT_URI, valuse);
+    }
+
+    public void testSetSingleChoiceItemsWithParamCursor() throws Throwable {
+        final String[] PROJECTION = new String[] {
+                People._ID, People.NAME
+        };
+        preparePeople();
+        final Cursor c = mContext.getContentResolver().query(People.CONTENT_URI, PROJECTION, null,
+                null, null);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setSingleChoiceItems(c, 0, People.NAME, mOnClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+                mListView.performItemClick(null, 0, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final CursorWrapper selected = (CursorWrapper)mListView.getSelectedItem();
+        assertEquals(c.getString(1), selected.getString(1));
+        assertTrue(mResult);
+    }
+
+    public void testSetSingleChoiceItemsWithParamCharSequence() throws Throwable {
+        final CharSequence[] items = mContext.getResources().getTextArray(
+                R.array.difficultyLevel);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setSingleChoiceItems(items, 0, mOnClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+                mSelectedItem = (CharSequence)mListView.getSelectedItem();
+                mListView.performItemClick(null, 0, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(items[0], mSelectedItem);
+        assertEquals(items[0], mListView.getItemAtPosition(0));
+        assertTrue(mResult);
+    }
+
+    public void testSetSingleChoiceItems() throws Throwable {
+        final CharSequence[] items = mContext.getResources().getTextArray(
+                R.array.difficultyLevel);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setSingleChoiceItems(new ArrayAdapter<CharSequence>(mContext,
+                        android.R.layout.select_dialog_singlechoice, android.R.id.text1, items), 0,
+                        mOnClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+                mSelectedItem = (CharSequence)mListView.getSelectedItem();
+                mListView.performItemClick(null, 0, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(items[0], mSelectedItem);
+        assertEquals(items[0], mListView.getItemAtPosition(0));
+        assertTrue(mResult);
+    }
+
+    public void testSetOnItemSelectedListener() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setOnItemSelectedListener(mOnItemSelectedListener);
+                mBuilder.setItems(R.array.difficultyLevel, mOnClickListener);
+                mDialog = mBuilder.show();
+                mListView = mDialog.getListView();
+                mListView.pointToPosition(0, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mItemSelected);
+    }
+
+    public void testSetView() throws Throwable {
+        final View view = new View(mContext);
+        view.setId(100);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setView(view);
+                mDialog = mBuilder.show();
+                mView = mDialog.getWindow().findViewById(100);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertEquals(view, mView);
+    }
+
+    public void testSetInverseBackgroundForced() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mBuilder.setInverseBackgroundForced(true);
+                mDialog = mBuilder.create();
+                mDialog.show();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testCreate() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mDialog = mBuilder.create();
+                mDialog.show();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertNotNull(mDialog);
+        assertTrue(mDialog.isShowing());
+    }
+
+    public void testShow() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mBuilder = new AlertDialog.Builder(mContext);
+                mDialog = mBuilder.show();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mDialog.isShowing());
+    }
+
+    private static class AdapterTest implements android.widget.ListAdapter {
+        public boolean areAllItemsEnabled() {
+            return true;
+        }
+
+        public boolean isEnabled(int position) {
+            return false;
+        }
+
+        public int getCount() {
+            return 0;
+        }
+
+        public Object getItem(int position) {
+            return null;
+        }
+
+        public long getItemId(int position) {
+            return 0;
+        }
+
+        public int getItemViewType(int position) {
+            return 0;
+        }
+
+        public android.view.View getView( int position,
+                                          android.view.View convertView,
+                                          android.view.ViewGroup parent){
+            return null;
+        }
+
+        public int getViewTypeCount() {
+            return 1;
+        }
+
+        public boolean hasStableIds() {
+            return false;
+        }
+
+        public boolean isEmpty() {
+            return true;
+        }
+
+        public void registerDataSetObserver(
+            android.database.DataSetObserver observer) {
+        }
+
+        public void unregisterDataSetObserver(
+            android.database.DataSetObserver observer) {
+        }
+    }
+}
diff --git a/tests/app/src/android/app/cts/AliasActivityStub.java b/tests/app/src/android/app/cts/AliasActivityStub.java
deleted file mode 100644
index 977bdc3..0000000
--- a/tests/app/src/android/app/cts/AliasActivityStub.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.cts;
-
-import android.app.AliasActivity;
-import android.os.Bundle;
-
-public class AliasActivityStub extends AliasActivity {
-
-    public static boolean isOnCreateCalled = false;
-    public static boolean isFinished = false;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        isOnCreateCalled = true;
-    }
-
-    @Override
-    public void finish() {
-        super.finish();
-        isFinished = true;
-    }
-}
diff --git a/tests/app/src/android/app/cts/AliasActivityTest.java b/tests/app/src/android/app/cts/AliasActivityTest.java
new file mode 100644
index 0000000..d3fe06c
--- /dev/null
+++ b/tests/app/src/android/app/cts/AliasActivityTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.AliasActivity;
+import android.app.stubs.AliasActivityStub;
+import android.app.stubs.ChildActivity;
+import android.content.Context;
+import android.content.Intent;
+import android.test.InstrumentationTestCase;
+
+public class AliasActivityTest extends InstrumentationTestCase {
+
+    private static final long SLEEP_TIME = 1000;
+
+    public void testAliasActivity() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                new AliasActivity();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        Context context = getInstrumentation().getTargetContext();
+
+        Intent intent = new Intent();
+        intent.setClass(context, AliasActivityStub.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        assertFalse(ChildActivity.isStarted);
+        assertFalse(AliasActivityStub.isOnCreateCalled);
+        context.startActivity(intent);
+        Thread.sleep(SLEEP_TIME);
+        assertTrue(AliasActivityStub.isOnCreateCalled);
+        assertTrue(ChildActivity.isStarted);
+        assertTrue(AliasActivityStub.isFinished);
+    }
+
+}
diff --git a/tests/app/src/android/app/cts/AppStubActivity.java b/tests/app/src/android/app/cts/AppStubActivity.java
deleted file mode 100644
index da5e55a..0000000
--- a/tests/app/src/android/app/cts/AppStubActivity.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ContextMenu.ContextMenuInfo;
-
-import com.android.cts.app.stub.R;
-
-/**
- * A minimal "Hello, World!" application.
- */
-public class AppStubActivity extends Activity {
-    private Dialog mDialog;
-    public boolean mOnPrepareDialog;
-    public boolean mOnOptionsMenuClosedCalled;
-    public boolean mOnPrepareOptionsMenuCalled;
-    public boolean mOnOptionsItemSelectedCalled;
-    public boolean mOnCreateOptionsMenu;
-    public boolean mIndterminate = false;
-    public boolean mIndterminatevisibility = false;
-    public boolean mSecPro = false;
-    public boolean mOnContextItemSelectedCalled;
-    public boolean mOnCreateContextMenu;
-    public boolean mApplyResourceCalled;
-    public boolean mCreateContextMenuCalled;
-    public boolean mRequestWinFeatureRet = false;
-
-    public AppStubActivity() {
-
-    }
-
-    public void finalize() {
-        try {
-            super.finalize();
-        } catch (Throwable exception) {
-            System.err.print("exception!");
-        }
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState){
-        super.onCreate(savedInstanceState);
-        mRequestWinFeatureRet = requestWindowFeature(1);
-        setContentView(R.layout.app_activity);
-    }
-
-    public Dialog getDialogById(int id) {
-        return mDialog;
-    }
-
-    @Override
-    public Dialog onCreateDialog(int id) {
-        super.onCreateDialog(id);
-        mDialog = new Dialog(this);
-        return mDialog;
-    }
-
-    @Override
-    protected void onPrepareDialog(int id, Dialog dialog) {
-        super.onPrepareDialog(id, dialog);
-        mOnPrepareDialog = true;
-    }
-
-    @Override
-    public void onOptionsMenuClosed(Menu menu) {
-        super.onOptionsMenuClosed(menu);
-        mOnOptionsMenuClosedCalled = true;
-    }
-
-    @Override
-    public boolean onPrepareOptionsMenu(Menu menu) {
-        mOnPrepareOptionsMenuCalled = true;
-        return super.onPrepareOptionsMenu(menu);
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        mOnCreateOptionsMenu = true;
-        if(menu != null)
-            menu.add(0, 0, 0, "Fake Item");
-        return super.onCreateOptionsMenu(menu);
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        mOnOptionsItemSelectedCalled = true;
-        return super.onOptionsItemSelected(item);
-    }
-
-    public boolean setProBarIndeterminate(boolean indeterminate){
-        mIndterminate = indeterminate;
-        super.setProgressBarIndeterminate(indeterminate);
-        return mIndterminate;
-    }
-
-    public boolean setProBarIndeterminateVisibility(boolean visible){
-        mIndterminatevisibility = visible;
-        super.setProgressBarIndeterminateVisibility(visible);
-        return mIndterminatevisibility;
-    }
-
-    public boolean setSecPro(int secPro){
-        mSecPro = true;
-        super.setSecondaryProgress(secPro);
-        return mSecPro;
-    }
-
-    @Override
-    public boolean onContextItemSelected(MenuItem item){
-        mOnContextItemSelectedCalled = true;
-        return super.onContextItemSelected(item);
-    }
-
-    @Override
-    public void onApplyThemeResource( Resources.Theme theme,
-                                      int resid,
-                                      boolean first){
-        super.onApplyThemeResource(theme,resid,first);
-        mApplyResourceCalled = true;
-    }
-
-    @Override
-    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
-        super.onCreateContextMenu(menu,v,menuInfo);
-        mCreateContextMenuCalled = true;
-    }
-}
-
diff --git a/tests/app/src/android/app/cts/ApplicationTest.java b/tests/app/src/android/app/cts/ApplicationTest.java
new file mode 100644
index 0000000..aaed064
--- /dev/null
+++ b/tests/app/src/android/app/cts/ApplicationTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Instrumentation;
+import android.app.stubs.MockApplication;
+import android.app.stubs.MockApplicationActivity;
+import android.app.stubs.OrientationTestUtils;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.test.InstrumentationTestCase;
+
+/**
+ * Test {@link Application}.
+ */
+public class ApplicationTest extends InstrumentationTestCase {
+
+    public void testApplication() throws Throwable {
+        final Instrumentation instrumentation = getInstrumentation();
+        final Context targetContext = instrumentation.getTargetContext();
+
+        final Intent intent = new Intent(targetContext, MockApplicationActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        final Activity activity = instrumentation.startActivitySync(intent);
+        final MockApplication mockApp = (MockApplication) activity.getApplication();
+        assertTrue(mockApp.isConstructorCalled);
+        assertTrue(mockApp.isOnCreateCalled);
+
+        //skip if the device doesn't support both of portrait and landscape orientation screens.
+        final PackageManager pm = targetContext.getPackageManager();
+        if(!(pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
+                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT))){
+            return;
+        }
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+               OrientationTestUtils.toggleOrientation(activity);
+            }
+        });
+        instrumentation.waitForIdleSync();
+        assertTrue(mockApp.isOnConfigurationChangedCalled);
+    }
+
+}
diff --git a/tests/app/src/android/app/cts/CTSActivityTestCaseBase.java b/tests/app/src/android/app/cts/CTSActivityTestCaseBase.java
deleted file mode 100644
index efe693a..0000000
--- a/tests/app/src/android/app/cts/CTSActivityTestCaseBase.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.cts.util.CTSResult;
-import android.test.InstrumentationTestCase;
-
-public class CTSActivityTestCaseBase extends InstrumentationTestCase implements CTSResult {
-
-    private Sync mSync;
-    static class Sync {
-        public boolean mHasNotify;
-        public int mResult;
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mSync = new Sync();
-    }
-
-    public void setResult(int resultCode) {
-        synchronized (mSync) {
-            mSync.mHasNotify = true;
-            mSync.mResult = resultCode;
-            mSync.notify();
-        }
-    }
-
-    protected void waitForResult() throws InterruptedException {
-        synchronized (mSync) {
-            while (!mSync.mHasNotify) {
-                mSync.wait();
-            }
-            assertEquals(CTSResult.RESULT_OK, mSync.mResult);
-        }
-    }
-}
diff --git a/tests/app/src/android/app/cts/ChildActivity.java b/tests/app/src/android/app/cts/ChildActivity.java
deleted file mode 100644
index 5f77655..0000000
--- a/tests/app/src/android/app/cts/ChildActivity.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.cts;
-
-import android.app.Activity;
-
-public class ChildActivity extends Activity {
-
-    public static boolean isStarted = false;
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-        isStarted = true;
-    }
-}
diff --git a/tests/app/src/android/app/cts/ChildTabActivity.java b/tests/app/src/android/app/cts/ChildTabActivity.java
deleted file mode 100644
index e3b2369..0000000
--- a/tests/app/src/android/app/cts/ChildTabActivity.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-
-/**
- * An empty activity for the TabActivity test
- */
-public class ChildTabActivity extends Activity {
-}
diff --git a/tests/app/src/android/app/cts/ClearTop.java b/tests/app/src/android/app/cts/ClearTop.java
deleted file mode 100644
index 5f608702..0000000
--- a/tests/app/src/android/app/cts/ClearTop.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-
-public class ClearTop extends Activity {
-    public static final String WAIT_CLEAR_TASK = "waitClearTask";
-    private static final String TAG = "ClearTop";
-    public ClearTop() {
-    }
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        final Intent intent = new Intent(getIntent()).setAction(LocalScreen.CLEAR_TASK).setClass(
-                this, LocalScreen.class);
-        startActivity(intent);
-    }
-
-    @Override
-    public void onNewIntent(Intent intent) {
-        Log.i(TAG, "onNewIntent");
-        if (LocalScreen.CLEAR_TASK.equals(intent.getAction())) {
-            setResult(RESULT_OK);
-        } else {
-            setResult(RESULT_CANCELED, new Intent().setAction("New intent received " + intent
-                    + ", expecting action " + TestedScreen.CLEAR_TASK));
-        }
-        finish();
-    }
-}
diff --git a/tests/app/src/android/app/cts/DialogStubActivity.java b/tests/app/src/android/app/cts/DialogStubActivity.java
deleted file mode 100644
index a773ae2..0000000
--- a/tests/app/src/android/app/cts/DialogStubActivity.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import com.android.cts.app.stub.R;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.DatePickerDialog;
-import android.app.Dialog;
-import android.app.TimePickerDialog;
-import android.app.DatePickerDialog.OnDateSetListener;
-import android.app.TimePickerDialog.OnTimeSetListener;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.DialogInterface.OnCancelListener;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.DatePicker;
-import android.widget.TimePicker;
-
-/*
- * Stub class for  Dialog, AlertDialog, DatePickerDialog, TimePickerDialog etc.
- */
-public class DialogStubActivity extends Activity {
-    public static final int TEST_DIALOG_WITHOUT_THEME = 0;
-    public static final int TEST_DIALOG_WITH_THEME = 1;
-    public static final int TEST_ALERTDIALOG = 2;
-    public static final int TEST_CUSTOM_ALERTDIALOG = 3;
-    public static final int TEST_DATEPICKERDIALOG = 4;
-    public static final int TEST_DATEPICKERDIALOG_WITH_THEME = 5;
-    public static final int TEST_TIMEPICKERDIALOG = 6;
-    public static final int TEST_TIMEPICKERDIALOG_WITH_THEME = 7;
-    public static final int TEST_ONSTART_AND_ONSTOP = 8;
-    public static final int TEST_ALERTDIALOG_DEPRECATED = 9;
-    public static final int TEST_ALERTDIALOG_CALLBACK = 10;
-    public static final int TEST_CUSTOM_ALERTDIALOG_VIEW = 11;
-    public static final int TEST_ALERTDIALOG_DEPRECATED_WITH_MESSAGE = 12;
-    public static final int TEST_ALERTDIALOG_THEME = 13;
-    public static final int TEST_ALERTDIALOG_CANCELABLE = 14;
-    public static final int TEST_ALERTDIALOG_NOT_CANCELABLE = 15;
-    public static final int TEST_PROTECTED_CANCELABLE = 16;
-    public static final int TEST_PROTECTED_NOT_CANCELABLE = 17;
-
-    public static final int SPACING_LEFT = 10;
-    public static final int SPACING_TOP = 20;
-    public static final int SPACING_RIGHT = 30;
-    public static final int SPACING_BOTTOM = 40;
-    public static int buttonIndex;
-
-    public static final String DEFAULT_ALERTDIALOG_TITLE = "AlertDialog";
-    public static final String DEFAULT_ALERTDIALOG_MESSAGE = "AlertDialog message";
-    private static final String LOG_TAG = "DialogStubActivity";
-
-    public boolean isPositiveButtonClicked = false;
-    public boolean isNegativeButtonClicked = false;
-    public boolean isNeutralButtonClicked = false;
-    public boolean isCallBackCalled;
-    public boolean onCancelCalled;
-    public boolean onKeyDownCalled;
-    public boolean onKeyUpCalled;
-    public boolean onCreateCalled;
-    public boolean onCancelListenerCalled;
-    public boolean onClickCalled;
-    public static boolean onDateChangedCalled;
-    public static boolean onRestoreInstanceStateCalled;
-    public boolean onSaveInstanceStateCalled;
-    public int updatedYear;
-    public int updatedMonth;
-    public int updatedDay;
-
-    public final int INITIAL_YEAR = 2008;
-    public final int INITIAL_MONTH = 7;
-    public final int INITIAL_DAY_OF_MONTH = 27;
-    private final int INITIAL_HOUR = 10;
-    private final int INITIAL_MINUTE = 35;
-    private Dialog mDialog;
-    private AlertDialog mAlertDialog;
-    private OnDateSetListener mOnDateSetListener = new OnDateSetListener() {
-        public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
-            updatedYear = year;
-            updatedMonth = monthOfYear;
-            updatedDay = dayOfMonth;
-        }
-    };
-
-    @SuppressWarnings("deprecation")
-    @Override
-    protected Dialog onCreateDialog(int id) {
-        switch (id) {
-            case TEST_DIALOG_WITHOUT_THEME:
-                mDialog = new Dialog(this);
-                mDialog.setTitle("Hello, Dialog");
-                break;
-
-            case TEST_DIALOG_WITH_THEME:
-                mDialog = new Dialog(this, 1);
-                break;
-
-            case TEST_ALERTDIALOG:
-                mDialog = getAlertDialogInstance(false);
-                break;
-
-            case TEST_CUSTOM_ALERTDIALOG:
-                mDialog = getCustomAlertDialogInstance(false);
-                break;
-
-            case TEST_CUSTOM_ALERTDIALOG_VIEW:
-                mDialog = getCustomAlertDialogInstance(true);
-                break;
-
-            case TEST_DATEPICKERDIALOG:
-                mDialog = new MockDatePickerDialog(this, mOnDateSetListener, INITIAL_YEAR,
-                        INITIAL_MONTH, INITIAL_DAY_OF_MONTH);
-                break;
-
-            case TEST_DATEPICKERDIALOG_WITH_THEME:
-                mDialog = new MockDatePickerDialog(this,
-                        com.android.internal.R.style.Theme_Translucent, mOnDateSetListener,
-                        INITIAL_YEAR, INITIAL_MONTH, INITIAL_DAY_OF_MONTH);
-                break;
-
-            case TEST_TIMEPICKERDIALOG:
-                mDialog = new TimePickerDialog(this, new OnTimeSetListener() {
-                    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
-                        isCallBackCalled = true;
-                    }
-                }, INITIAL_HOUR, INITIAL_MINUTE, true);
-                break;
-
-            case TEST_TIMEPICKERDIALOG_WITH_THEME:
-                mDialog = new TimePickerDialog(this,
-                        com.android.internal.R.style.Theme_Translucent, null, INITIAL_HOUR,
-                        INITIAL_MINUTE, true);
-                break;
-
-            case TEST_ONSTART_AND_ONSTOP:
-                mDialog = new TestDialog(this);
-                Log.i(LOG_TAG, "mTestDialog:" + mDialog);
-                return mDialog;
-
-            case TEST_ALERTDIALOG_DEPRECATED:
-                mDialog = getAlertDialogInstance(true);
-                break;
-
-            case TEST_ALERTDIALOG_DEPRECATED_WITH_MESSAGE:
-                final Handler handler = new Handler() {
-                    @Override
-                    public void handleMessage(Message msg) {
-                        buttonIndex = msg.what;
-                        super.handleMessage(msg);
-                    }
-                };
-                final Message positiveMessage = Message.obtain();
-                positiveMessage.setTarget(handler);
-                positiveMessage.what = DialogInterface.BUTTON_POSITIVE;
-
-                final Message negativeMessage = Message.obtain();
-                negativeMessage.setTarget(handler);
-                negativeMessage.what = DialogInterface.BUTTON_NEGATIVE;
-
-                final Message neutralMessage = Message.obtain();
-                neutralMessage.setTarget(handler);
-                neutralMessage.what = DialogInterface.BUTTON_NEUTRAL;
-                mAlertDialog = getAlertDialogInstance(false);
-                mAlertDialog.setButton(getString(R.string.alert_dialog_positive), positiveMessage);
-                mAlertDialog.setButton2(getString(R.string.alert_dialog_negative), negativeMessage);
-                mAlertDialog.setButton3(getString(R.string.alert_dialog_neutral), neutralMessage);
-                mDialog = mAlertDialog;
-                break;
-
-            case TEST_ALERTDIALOG_CALLBACK:
-                mDialog = new MockAlertDialog(this);
-                break;
-            case TEST_ALERTDIALOG_THEME:
-                mDialog = new MockAlertDialog(this, R.style.Theme_AlertDialog);
-                break;
-            case TEST_ALERTDIALOG_CANCELABLE:
-                mDialog = getAlertDialogCancelablInstance(true);
-                break;
-            case TEST_ALERTDIALOG_NOT_CANCELABLE:
-                mDialog = getAlertDialogCancelablInstance(false);
-                break;
-            case TEST_PROTECTED_CANCELABLE:
-                mDialog = new TestDialog(this, true, new OnCancelListener() {
-                    public void onCancel(DialogInterface dialog) {
-                        onCancelListenerCalled = true;
-                    }
-                });
-                break;
-            case TEST_PROTECTED_NOT_CANCELABLE:
-                mDialog = new TestDialog(this, false, new OnCancelListener() {
-                    public void onCancel(DialogInterface dialog) {
-                        onCancelListenerCalled = true;
-                    }
-                });
-                break;
-            default:
-                break;
-        }
-
-        Log.i(LOG_TAG, "mDialog:" + mDialog);
-        return mDialog;
-    }
-
-    private AlertDialog getAlertDialogCancelablInstance(boolean cancelable) {
-        OnCancelListener cancelListener = new OnCancelListener() {
-            public void onCancel(DialogInterface dialog) {
-                onCancelCalled = true;
-            }
-        };
-        return new MockAlertDialog(this, cancelable, cancelListener);
-    }
-
-    @SuppressWarnings("deprecation")
-    private AlertDialog getAlertDialogInstance(boolean deprecated) {
-        mAlertDialog = new AlertDialog.Builder(DialogStubActivity.this).create();
-        mAlertDialog.setIcon(com.android.cts.app.stub.R.drawable.pass);
-        mAlertDialog.setTitle(DEFAULT_ALERTDIALOG_TITLE);
-        mAlertDialog.setMessage(DEFAULT_ALERTDIALOG_MESSAGE);
-        mAlertDialog.setInverseBackgroundForced(true);
-        final DialogInterface.OnClickListener positiveListener = new MockOnClickListener(
-                DialogInterface.BUTTON_POSITIVE);
-        final DialogInterface.OnClickListener netativeListener = new MockOnClickListener(
-                DialogInterface.BUTTON_NEGATIVE);
-        final DialogInterface.OnClickListener neutralListener = new MockOnClickListener(
-                DialogInterface.BUTTON_NEUTRAL);
-
-        if (deprecated) {
-            mAlertDialog.setButton(getString(R.string.alert_dialog_positive), positiveListener);
-            mAlertDialog.setButton2(getString(R.string.alert_dialog_negative), netativeListener);
-            mAlertDialog.setButton3(getString(R.string.alert_dialog_neutral), neutralListener);
-        } else {
-            mAlertDialog.setButton(DialogInterface.BUTTON_POSITIVE,
-                    getString(R.string.alert_dialog_positive), positiveListener);
-            mAlertDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
-                    getString(R.string.alert_dialog_negative), netativeListener);
-            mAlertDialog.setButton(DialogInterface.BUTTON_NEUTRAL,
-                    getString(R.string.alert_dialog_neutral), neutralListener);
-        }
-        return mAlertDialog;
-
-    }
-
-    private AlertDialog getCustomAlertDialogInstance(boolean withSpacing) {
-        final LayoutInflater inflate = getLayoutInflater();
-        final View customTitleViewCustom = inflate.inflate(R.layout.alertdialog_custom_title, null);
-        final View textEntryView = inflate.inflate(R.layout.alert_dialog_text_entry_2, null);
-        mAlertDialog = new AlertDialog.Builder(DialogStubActivity.this).create();
-        mAlertDialog.setCustomTitle(customTitleViewCustom);
-        mAlertDialog.setMessage(DEFAULT_ALERTDIALOG_MESSAGE);
-        if (withSpacing) {
-            mAlertDialog.setView(textEntryView, SPACING_LEFT, SPACING_TOP, SPACING_RIGHT,
-                    SPACING_BOTTOM);
-        } else {
-            mAlertDialog.setView(textEntryView);
-        }
-
-        return mAlertDialog;
-
-    }
-
-    public Dialog getDialog() {
-        return mDialog;
-    }
-
-    public String getDialogTitle() {
-        return (String) mDialog.getWindow().getAttributes().getTitle();
-    }
-
-    private static final String TEST_DIALOG_NUMBER_EXTRA = "testDialogNumber";
-
-    public static <T extends Activity> T startDialogActivity(
-            ActivityInstrumentationTestCase2<T> testCase, int dialogNumber) {
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.putExtra(TEST_DIALOG_NUMBER_EXTRA, dialogNumber);
-        testCase.setActivityIntent(intent);
-        return testCase.getActivity();
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.dialog_stub_layout);
-
-        Intent intent = getIntent();
-        int dialogNum = intent.getIntExtra(TEST_DIALOG_NUMBER_EXTRA, -1);
-        if (dialogNum != -1) {
-            showDialog(dialogNum);
-        }
-    }
-
-    public void setUpTitle(final String title) {
-        runOnUiThread(new Runnable() {
-            public void run() {
-                getDialog().setTitle(title);
-            }
-        });
-    }
-
-    public void setUpTitle(final int id) {
-        runOnUiThread(new Runnable() {
-            public void run() {
-                getDialog().setTitle(id);
-            }
-        });
-    }
-
-    class MockAlertDialog extends AlertDialog {
-        public MockAlertDialog(Context context) {
-            super(context);
-        }
-
-        public MockAlertDialog(Context context, int theme) {
-            super(context, theme);
-        }
-
-        public MockAlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
-            super(context, cancelable, cancelListener);
-        }
-
-        @Override
-        public boolean onKeyDown(int keyCode, KeyEvent event) {
-            onKeyDownCalled = true;
-            return super.onKeyDown(keyCode, event);
-        }
-
-        @Override
-        public boolean onKeyUp(int keyCode, KeyEvent event) {
-            onKeyUpCalled = true;
-            return super.onKeyUp(keyCode, event);
-        }
-
-        @Override
-        protected void onCreate(Bundle savedInstanceState) {
-            onCreateCalled = true;
-            super.onCreate(savedInstanceState);
-        }
-
-    }
-
-    class MockOnClickListener implements DialogInterface.OnClickListener {
-        private final int mId;
-
-        public MockOnClickListener(final int buttonId) {
-            mId = buttonId;
-        }
-
-        public void onClick(DialogInterface dialog, int which) {
-            switch (mId) {
-                case DialogInterface.BUTTON_POSITIVE:
-                    isPositiveButtonClicked = true;
-                    break;
-                case DialogInterface.BUTTON_NEGATIVE:
-                    isNegativeButtonClicked = true;
-                    break;
-                case DialogInterface.BUTTON_NEUTRAL:
-                    isNeutralButtonClicked = true;
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
-
-    class MockDatePickerDialog extends DatePickerDialog {
-        public MockDatePickerDialog(Context context, OnDateSetListener callBack, int year,
-                int monthOfYear, int dayOfMonth) {
-            super(context, callBack, year, monthOfYear, dayOfMonth);
-        }
-
-        public MockDatePickerDialog(Context context, int theme, OnDateSetListener callBack,
-                int year, int monthOfYear, int dayOfMonth) {
-            super(context, theme, callBack, year, monthOfYear, dayOfMonth);
-        }
-
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-            onClickCalled = true;
-            super.onClick(dialog, which);
-        }
-
-        @Override
-        public void onDateChanged(DatePicker view, int year, int month, int day) {
-            onDateChangedCalled = true;
-            super.onDateChanged(view, year, month, day);
-        }
-
-        @Override
-        public void onRestoreInstanceState(Bundle savedInstanceState) {
-            onRestoreInstanceStateCalled = true;
-            super.onRestoreInstanceState(savedInstanceState);
-        }
-
-        @Override
-        public Bundle onSaveInstanceState() {
-            onSaveInstanceStateCalled = true;
-            return super.onSaveInstanceState();
-        }
-
-    }
-}
diff --git a/tests/app/src/android/app/cts/DialogTest.java b/tests/app/src/android/app/cts/DialogTest.java
new file mode 100644
index 0000000..473835c
--- /dev/null
+++ b/tests/app/src/android/app/cts/DialogTest.java
@@ -0,0 +1,932 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.cts;
+
+import android.app.Dialog;
+import android.app.Instrumentation;
+import android.app.stubs.DialogStubActivity;
+import android.app.stubs.OrientationTestUtils;
+import android.app.stubs.TestDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.DialogInterface.OnDismissListener;
+import android.content.DialogInterface.OnKeyListener;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.cts.util.PollingCheck;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+
+import android.app.stubs.R;
+
+import java.lang.ref.WeakReference;
+
+public class DialogTest extends ActivityInstrumentationTestCase2<DialogStubActivity> {
+
+    protected static final long SLEEP_TIME = 200;
+    private static final String STUB_ACTIVITY_PACKAGE = "android.app.stubs";
+    private static final long TEST_TIMEOUT = 1000L;
+
+    /**
+     *  please refer to Dialog
+     */
+    private static final int DISMISS = 0x43;
+    private static final int CANCEL = 0x44;
+
+    private boolean mCalledCallback;
+    private boolean mIsKey0Listened;
+    private boolean mIsKey1Listened;
+    private boolean mOnCancelListenerCalled;
+
+    private Instrumentation mInstrumentation;
+    private Context mContext;
+    private DialogStubActivity mActivity;
+
+
+    public DialogTest() {
+        super(STUB_ACTIVITY_PACKAGE, DialogStubActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mContext = mInstrumentation.getContext();
+    }
+
+    private void startDialogActivity(int dialogNumber) {
+        mActivity = DialogStubActivity.startDialogActivity(this, dialogNumber);
+    }
+
+    @UiThreadTest
+    public void testConstructor() {
+        new Dialog(mContext);
+        Dialog d = new Dialog(mContext, 0);
+        // According to javadoc of constructors, it will set theme to system default theme,
+        // when we set no theme id or set it theme id to 0.
+        // But CTS can no assert dialog theme equals system internal theme.
+
+        d = new Dialog(mContext, R.style.TextAppearance);
+        TypedArray ta =
+            d.getContext().getTheme().obtainStyledAttributes(R.styleable.TextAppearance);
+        assertTextAppearanceStyle(ta);
+
+        final Window w = d.getWindow();
+        ta = w.getContext().getTheme().obtainStyledAttributes(R.styleable.TextAppearance);
+        assertTextAppearanceStyle(ta);
+    }
+
+    public void testConstructor_protectedCancellable() {
+        startDialogActivity(DialogStubActivity.TEST_PROTECTED_CANCELABLE);
+        mActivity.onCancelListenerCalled = false;
+        sendKeys(KeyEvent.KEYCODE_BACK);
+        assertTrue(mActivity.onCancelListenerCalled);
+    }
+
+    public void testConstructor_protectedNotCancellable() {
+        startDialogActivity(DialogStubActivity.TEST_PROTECTED_NOT_CANCELABLE);
+        mActivity.onCancelListenerCalled = false;
+        sendKeys(KeyEvent.KEYCODE_BACK);
+        assertFalse(mActivity.onCancelListenerCalled);
+    }
+
+    private void assertTextAppearanceStyle(TypedArray ta) {
+        final int defValue = -1;
+        // get Theme and assert
+        final Resources.Theme expected = mContext.getResources().newTheme();
+        expected.setTo(mContext.getTheme());
+        expected.applyStyle(R.style.TextAppearance, true);
+        TypedArray expectedTa = expected.obtainStyledAttributes(R.styleable.TextAppearance);
+        assertEquals(expectedTa.getIndexCount(), ta.getIndexCount());
+        assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColor, defValue),
+                ta.getColor(R.styleable.TextAppearance_textColor, defValue));
+        assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColorHint, defValue),
+                ta.getColor(R.styleable.TextAppearance_textColorHint, defValue));
+        assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColorLink, defValue),
+                ta.getColor(R.styleable.TextAppearance_textColorLink, defValue));
+        assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColorHighlight, defValue),
+                ta.getColor(R.styleable.TextAppearance_textColorHighlight, defValue));
+        assertEquals(expectedTa.getDimension(R.styleable.TextAppearance_textSize, defValue),
+                ta.getDimension(R.styleable.TextAppearance_textSize, defValue));
+        assertEquals(expectedTa.getInt(R.styleable.TextAppearance_textStyle, defValue),
+                ta.getInt(R.styleable.TextAppearance_textStyle, defValue));
+    }
+
+    public void testOnStartCreateStop(){
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+
+        assertTrue(d.isOnStartCalled);
+        assertTrue(d.isOnCreateCalled);
+
+        assertFalse(d.isOnStopCalled);
+        sendKeys(KeyEvent.KEYCODE_BACK);
+        assertTrue(d.isOnStopCalled);
+    }
+
+    public void testAccessOwnerActivity() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        Dialog d = mActivity.getDialog();
+        assertNotNull(d);
+        assertSame(mActivity, d.getOwnerActivity());
+        d.setVolumeControlStream(d.getVolumeControlStream() + 1);
+        assertEquals(d.getOwnerActivity().getVolumeControlStream() + 1, d.getVolumeControlStream());
+
+        try {
+            d.setOwnerActivity(null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                Dialog dialog = new Dialog(mContext);
+                assertNull(dialog.getOwnerActivity());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testShow() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        final Dialog d = mActivity.getDialog();
+        final View decor = d.getWindow().getDecorView();
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.hide();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(View.GONE, decor.getVisibility());
+        assertTrue(d.isShowing());
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.show();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(View.VISIBLE, decor.getVisibility());
+        assertTrue(d.isShowing());
+        dialogDismiss(d);
+        assertFalse(d.isShowing());
+    }
+
+    public void testOnSaveInstanceState() {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+
+        assertFalse(d.isOnSaveInstanceStateCalled);
+        assertFalse(TestDialog.isOnRestoreInstanceStateCalled);
+
+        //skip if the device doesn't support both of portrait and landscape orientation screens.
+        final PackageManager pm = mContext.getPackageManager();
+        if(!(pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
+                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT))){
+            return;
+        }
+
+        OrientationTestUtils.toggleOrientationSync(mActivity, mInstrumentation);
+
+        assertTrue(d.isOnSaveInstanceStateCalled);
+        assertTrue(TestDialog.isOnRestoreInstanceStateCalled);
+    }
+
+    public void testGetCurrentFocus() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+        assertNull(d.getCurrentFocus());
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.takeKeyEvents(true);
+                d.setContentView(R.layout.alert_dialog_text_entry);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        sendKeys(KeyEvent.KEYCODE_0);
+        // When mWindow is not null getCUrrentFocus is the view in dialog
+        assertEquals(d.getWindow().getCurrentFocus(), d.getCurrentFocus());
+    }
+
+    public void testSetContentView() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        final Dialog d = mActivity.getDialog();
+        assertNotNull(d);
+
+        // set content view to a four elements layout
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.setContentView(R.layout.alert_dialog_text_entry);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // check if four elements are right there
+        assertNotNull(d.findViewById(R.id.username_view));
+        assertNotNull(d.findViewById(R.id.username_edit));
+        assertNotNull(d.findViewById(R.id.password_view));
+        assertNotNull(d.findViewById(R.id.password_edit));
+
+        final LayoutInflater inflate1 = d.getLayoutInflater();
+
+        // set content view to a two elements layout
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.setContentView(inflate1.inflate(R.layout.alert_dialog_text_entry_2, null));
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // check if only two elements are right there
+        assertNotNull(d.findViewById(R.id.username_view));
+        assertNotNull(d.findViewById(R.id.username_edit));
+        assertNull(d.findViewById(R.id.password_view));
+        assertNull(d.findViewById(R.id.password_edit));
+
+        final WindowManager.LayoutParams lp = d.getWindow().getAttributes();
+        final LayoutInflater inflate2 = mActivity.getLayoutInflater();
+
+        // set content view to a four elements layout
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.setContentView(inflate2.inflate(R.layout.alert_dialog_text_entry, null), lp);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // check if four elements are right there
+        assertNotNull(d.findViewById(R.id.username_view));
+        assertNotNull(d.findViewById(R.id.username_edit));
+        assertNotNull(d.findViewById(R.id.password_view));
+        assertNotNull(d.findViewById(R.id.password_edit));
+
+        final WindowManager.LayoutParams lp2 = d.getWindow().getAttributes();
+        final LayoutInflater inflate3 = mActivity.getLayoutInflater();
+        lp2.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        lp2.width = ViewGroup.LayoutParams.WRAP_CONTENT;
+
+        // add a check box view
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.addContentView(inflate3.inflate(R.layout.checkbox_layout, null), lp2);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // check if four elements are right there, and new add view there.
+        assertNotNull(d.findViewById(R.id.check_box));
+        assertNotNull(d.findViewById(R.id.username_view));
+        assertNotNull(d.findViewById(R.id.username_edit));
+        assertNotNull(d.findViewById(R.id.password_view));
+        assertNotNull(d.findViewById(R.id.password_edit));
+    }
+
+    public void testSetTitle() {
+        final String expectedTitle = "Test Dialog Without theme";
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+
+        assertNotNull(mActivity.getDialog());
+        mActivity.setUpTitle(expectedTitle);
+        mInstrumentation.waitForIdleSync();
+
+        final Dialog d = mActivity.getDialog();
+        assertEquals(expectedTitle, (String) d.getWindow().getAttributes().getTitle());
+
+        mActivity.setUpTitle(R.string.hello_android);
+        mInstrumentation.waitForIdleSync();
+        assertEquals(mActivity.getResources().getString(R.string.hello_android),
+                (String) d.getWindow().getAttributes().getTitle());
+    }
+
+    public void testOnKeyDownKeyUp() {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+        assertFalse(d.isOnKeyDownCalled);
+        assertFalse(d.isOnKeyUpCalled);
+
+        // send key 0 down and up events, onKeyDown return false
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
+        assertTrue(d.isOnKeyDownCalled);
+        assertTrue(d.isOnKeyUpCalled);
+        assertEquals(KeyEvent.KEYCODE_0, d.keyDownCode);
+        assertFalse(d.onKeyDownReturn);
+
+        // send key back down and up events, onKeyDown return true
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        assertEquals(KeyEvent.KEYCODE_BACK, d.keyDownCode);
+        assertTrue(d.onKeyDownReturn);
+    }
+
+     public void testOnKeyMultiple() {
+         startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+         final TestDialog d = (TestDialog) mActivity.getDialog();
+
+         assertNull(d.keyMultipleEvent);
+         d.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_UNKNOWN));
+         assertTrue(d.isOnKeyMultipleCalled);
+         assertFalse(d.onKeyMultipleReturn);
+         assertEquals(KeyEvent.KEYCODE_UNKNOWN, d.keyMultipleEvent.getKeyCode());
+         assertEquals(KeyEvent.ACTION_MULTIPLE, d.keyMultipleEvent.getAction());
+     }
+
+    public void testTouchEvent() {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+
+        assertNull(d.onTouchEvent);
+        assertNull(d.touchEvent);
+        assertFalse(d.isOnTouchEventCalled);
+
+        // Send a touch event outside the activity.  The event will be ignored
+        // because closeOnTouchOutside is false.
+        d.setCanceledOnTouchOutside(false);
+
+        long now = SystemClock.uptimeMillis();
+        MotionEvent touchMotionEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
+                1, 100, 0);
+        mInstrumentation.sendPointerSync(touchMotionEvent);
+
+        new PollingCheck(TEST_TIMEOUT) {
+            protected boolean check() {
+                return !d.dispatchTouchEventResult;
+            }
+        }.run();
+
+        assertMotionEventEquals(touchMotionEvent, d.touchEvent);
+
+        assertTrue(d.isOnTouchEventCalled);
+        assertMotionEventEquals(touchMotionEvent, d.onTouchEvent);
+        d.isOnTouchEventCalled = false;
+        assertTrue(d.isShowing());
+
+        // Watch activities cover the entire screen, so there is no way to touch outside.
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            // Send a touch event outside the activity.  This time the dialog will be dismissed
+            // because closeOnTouchOutside is true.
+            d.setCanceledOnTouchOutside(true);
+
+            touchMotionEvent = MotionEvent.obtain(now, now + 1, MotionEvent.ACTION_DOWN,
+                    1, 100, 0);
+            mInstrumentation.sendPointerSync(touchMotionEvent);
+
+            new PollingCheck(TEST_TIMEOUT) {
+                protected boolean check() {
+                    return d.dispatchTouchEventResult;
+                }
+            }.run();
+
+            assertMotionEventEquals(touchMotionEvent, d.touchEvent);
+
+            assertTrue(d.isOnTouchEventCalled);
+            assertMotionEventEquals(touchMotionEvent, d.onTouchEvent);
+            assertFalse(d.isShowing());
+        }
+    }
+
+    public void testTrackballEvent() {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+        long eventTime = SystemClock.uptimeMillis();
+        final MotionEvent trackBallEvent = MotionEvent.obtain(eventTime, eventTime,
+                MotionEvent.ACTION_DOWN, 0.0f, 0.0f, 0);
+
+        assertNull(d.trackballEvent);
+        assertNull(d.onTrackballEvent);
+
+        assertFalse(d.isOnTrackballEventCalled);
+        mInstrumentation.sendTrackballEventSync(trackBallEvent);
+        assertTrue(d.isOnTrackballEventCalled);
+        assertMotionEventEquals(trackBallEvent, d.trackballEvent);
+        assertMotionEventEquals(trackBallEvent, d.onTrackballEvent);
+
+    }
+
+    private void assertMotionEventEquals(final MotionEvent expected, final MotionEvent actual) {
+        assertEquals(expected.getDownTime(), actual.getDownTime());
+        assertEquals(expected.getEventTime(), actual.getEventTime());
+        assertEquals(expected.getAction(), actual.getAction());
+        assertEquals(expected.getMetaState(), actual.getMetaState());
+        assertEquals(expected.getSize(), actual.getSize());
+        // As MotionEvent doc says the value of X and Y coordinate may have
+        // a fraction for input devices that are sub-pixel precise,
+        // so we won't assert them here.
+    }
+
+    public void testOnWindowAttributesChanged() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+
+        assertTrue(d.isOnWindowAttributesChangedCalled);
+        d.isOnWindowAttributesChangedCalled = false;
+
+        final WindowManager.LayoutParams lp = d.getWindow().getAttributes();
+        lp.setTitle("test OnWindowAttributesChanged");
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.getWindow().setAttributes(lp);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(d.isOnWindowAttributesChangedCalled);
+        assertSame(lp, d.getWindow().getAttributes());
+    }
+
+    public void testOnContentChanged() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+        assertNotNull(d);
+
+        assertFalse(d.isOnContentChangedCalled);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.setContentView(R.layout.alert_dialog_text_entry);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(d.isOnContentChangedCalled);
+    }
+
+    public void testOnWindowFocusChanged() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+        assertTrue(d.isOnWindowFocusChangedCalled);
+        d.isOnWindowFocusChangedCalled = false;
+
+        // show a new dialog, the new dialog get focus
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mActivity.showDialog(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Wait until TestDialog#OnWindowFocusChanged() is called
+        new PollingCheck(TEST_TIMEOUT) {
+            protected boolean check() {
+                return d.isOnWindowFocusChangedCalled;
+            }
+        }.run();
+    }
+
+    public void testDispatchKeyEvent() {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+
+        sendKeys(KeyEvent.KEYCODE_0);
+        assertFalse(d.dispatchKeyEventResult);
+        assertEquals(KeyEvent.KEYCODE_0, d.keyEvent.getKeyCode());
+
+        d.setOnKeyListener(new OnKeyListener() {
+            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+                if (KeyEvent.ACTION_DOWN == event.getAction()) {
+                    if (KeyEvent.KEYCODE_0 == keyCode) {
+                        mIsKey0Listened = true;
+                        return true;
+                    }
+
+                    if (KeyEvent.KEYCODE_1 == keyCode) {
+                        mIsKey1Listened = true;
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+        });
+
+        mIsKey1Listened = false;
+        sendKeys(KeyEvent.KEYCODE_1);
+        assertTrue(mIsKey1Listened);
+
+        mIsKey0Listened = false;
+        sendKeys(KeyEvent.KEYCODE_0);
+        assertTrue(mIsKey0Listened);
+    }
+
+    /*
+     * Test point
+     * 1. registerForContextMenu() will OnCreateContextMenuListener on the view to this activity,
+     * so onCreateContextMenu() will be called when it is time to show the context menu.
+     * 2. Close context menu will make onPanelClosed to be called,
+     * and onPanelClosed will calls through to the new onPanelClosed method.
+     * 3. unregisterForContextMenu() will remove the OnCreateContextMenuListener on the view,
+     * so onCreateContextMenu() will not be called when try to open context menu.
+     * 4. Selected a item of context menu will make onMenuItemSelected() to be called,
+     * and onMenuItemSelected will calls through to the new onContextItemSelected method.
+     * 5. onContextMenuClosed is called whenever the context menu is being closed (either by
+     * the user canceling the menu with the back/menu button, or when an item is selected).
+     */
+    public void testContextMenu() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+        final LinearLayout parent = new LinearLayout(mContext);
+        final MockView v = new MockView(mContext);
+        parent.addView(v);
+        assertFalse(v.isShowContextMenuCalled);
+        // Register for context menu and open it
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.addContentView(parent, new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT));
+                d.registerForContextMenu(v);
+                d.openContextMenu(v);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(v.isShowContextMenuCalled);
+        assertTrue(d.isOnCreateContextMenuCalled);
+
+        assertFalse(d.isOnPanelClosedCalled);
+        assertFalse(d.isOnContextMenuClosedCalled);
+        // Closed context menu
+        sendKeys(KeyEvent.KEYCODE_BACK);
+        assertTrue(d.isOnPanelClosedCalled);
+        // Here isOnContextMenuClosedCalled should be true, see bug 1716918.
+        assertFalse(d.isOnContextMenuClosedCalled);
+
+        v.isShowContextMenuCalled = false;
+        d.isOnCreateContextMenuCalled = false;
+        // Unregister for context menu, and try to open it
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.unregisterForContextMenu(v);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.openContextMenu(v);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(v.isShowContextMenuCalled);
+        assertFalse(d.isOnCreateContextMenuCalled);
+
+        // Register for context menu and open it again
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.registerForContextMenu(v);
+                d.openContextMenu(v);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertFalse(d.isOnContextItemSelectedCalled);
+        assertFalse(d.isOnMenuItemSelectedCalled);
+        d.isOnPanelClosedCalled = false;
+        assertFalse(d.isOnContextMenuClosedCalled);
+        // select a context menu item
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        assertTrue(d.isOnMenuItemSelectedCalled);
+        // Here isOnContextItemSelectedCalled should be true, see bug 1716918.
+        assertFalse(d.isOnContextItemSelectedCalled);
+        assertTrue(d.isOnPanelClosedCalled);
+        // Here isOnContextMenuClosedCalled should be true, see bug 1716918.
+        assertFalse(d.isOnContextMenuClosedCalled);
+    }
+
+    public void testOnSearchRequested() {
+    }
+
+    public void testTakeKeyEvents() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+        final View v = d.getWindow().getDecorView();
+        assertNull(d.getCurrentFocus());
+        takeKeyEvents(d, true);
+        assertTrue(v.isFocusable());
+        sendKeys(KeyEvent.KEYCODE_0);
+        assertEquals(KeyEvent.KEYCODE_0, d.keyEvent.getKeyCode());
+        d.keyEvent = null;
+
+        takeKeyEvents(d, false);
+        assertNull(d.getCurrentFocus());
+        assertFalse(v.isFocusable());
+        sendKeys(KeyEvent.KEYCODE_0);
+        // d.keyEvent should be null
+    }
+
+    private void takeKeyEvents(final Dialog d, final boolean get) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.takeKeyEvents(get);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testRequestWindowFeature() {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        // called requestWindowFeature at TestDialog onCreate method
+        assertTrue(((TestDialog) mActivity.getDialog()).isRequestWindowFeature);
+    }
+
+    public void testSetFeatureDrawableResource() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mActivity.getDialog().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
+                        R.drawable.robot);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testSetFeatureDrawableUri() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mActivity.getDialog().setFeatureDrawableUri(Window.FEATURE_LEFT_ICON,
+                        Uri.parse("http://www.google.com"));
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testSetFeatureDrawable() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mActivity.getDialog().setFeatureDrawable(Window.FEATURE_LEFT_ICON, 
+                        new MockDrawable());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testSetFeatureDrawableAlpha() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mActivity.getDialog().setFeatureDrawableAlpha(Window.FEATURE_LEFT_ICON, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void testGetLayoutInflater() {
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        final Dialog d = mActivity.getDialog();
+        assertEquals(d.getWindow().getLayoutInflater(), d.getLayoutInflater());
+    }
+
+    public void testSetCancelable_true() {
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        final Dialog d = mActivity.getDialog();
+
+        d.setCancelable(true);
+        assertTrue(d.isShowing());
+        sendKeys(KeyEvent.KEYCODE_BACK);
+        assertFalse(d.isShowing());
+    }
+
+    public void testSetCancellable_false() {
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        final Dialog d = mActivity.getDialog();
+
+        d.setCancelable(false);
+        assertTrue(d.isShowing());
+        sendKeys(KeyEvent.KEYCODE_BACK);
+        assertTrue(d.isShowing());
+    }
+
+    /*
+     * Test point
+     * 1. Cancel the dialog.
+     * 2. Set a listener to be invoked when the dialog is canceled.
+     */
+    public void testCancel_listener() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        final Dialog d = mActivity.getDialog();
+
+        assertTrue(d.isShowing());
+        mOnCancelListenerCalled = false;
+        d.setOnCancelListener(new OnCancelListener() {
+            public void onCancel(DialogInterface dialog) {
+                mOnCancelListenerCalled = true;
+            }
+        });
+        dialogCancel(d);
+
+        assertFalse(d.isShowing());
+        assertTrue(mOnCancelListenerCalled);
+    }
+
+    public void testCancel_noListener() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        final Dialog d = mActivity.getDialog();
+
+        assertTrue(d.isShowing());
+        mOnCancelListenerCalled = false;
+        d.setOnCancelListener(null);
+        dialogCancel(d);
+
+        assertFalse(d.isShowing());
+        assertFalse(mOnCancelListenerCalled);
+    }
+
+    public void testSetCancelMessage() throws Exception {
+        mCalledCallback = false;
+        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+        final TestDialog d = (TestDialog) mActivity.getDialog();
+        final HandlerThread ht = new HandlerThread("DialogTest");
+        ht.start();
+
+        d.setCancelMessage(new MockDismissCancelHandler(d, ht.getLooper()).obtainMessage(CANCEL,
+                new OnCancelListener() {
+                    public void onCancel(DialogInterface dialog) {
+                        mCalledCallback = true;
+                    }
+                }));
+        assertTrue(d.isShowing());
+        assertFalse(mCalledCallback);
+        sendKeys(KeyEvent.KEYCODE_BACK);
+        assertTrue(mCalledCallback);
+        assertFalse(d.isShowing());
+
+        ht.join(100);
+    }
+
+    /*
+     * Test point
+     * 1. Set a listener to be invoked when the dialog is dismissed.
+     * 2. set onDismissListener to null, it will not changed flag after dialog dismissed.
+     */
+    public void testSetOnDismissListener_listener() throws Throwable {
+        mCalledCallback = false;
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        final Dialog d = mActivity.getDialog();
+
+        d.setOnDismissListener(new OnDismissListener() {
+            public void onDismiss(DialogInterface dialog) {
+                mCalledCallback = true;
+            }
+        });
+
+        assertTrue(d.isShowing());
+        assertFalse(mCalledCallback);
+        dialogDismiss(d);
+        assertTrue(mCalledCallback);
+        assertFalse(d.isShowing());
+    }
+
+    public void testSetOnDismissListener_noListener() throws Throwable {
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        final Dialog d = mActivity.getDialog();
+        assertTrue(d.isShowing());
+        mCalledCallback = false;
+        d.setOnDismissListener(null);
+        dialogDismiss(d);
+        assertFalse(mCalledCallback);
+        assertFalse(d.isShowing());
+    }
+
+    public void testSetDismissMessage() throws Throwable {
+        mCalledCallback = false;
+        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
+        final Dialog d = mActivity.getDialog();
+
+        final HandlerThread ht = new HandlerThread("DialogTest");
+        ht.start();
+
+        d.setDismissMessage(new MockDismissCancelHandler(d, ht.getLooper()).obtainMessage(DISMISS,
+                new OnDismissListener() {
+                    public void onDismiss(DialogInterface dialog) {
+                        mCalledCallback = true;
+                    }
+                }));
+        assertTrue(d.isShowing());
+        assertFalse(mCalledCallback);
+        dialogDismiss(d);
+        ht.join(100);
+        assertTrue(mCalledCallback);
+        assertFalse(d.isShowing());
+    }
+
+    private void dialogDismiss(final Dialog d) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.dismiss();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void dialogCancel(final Dialog d) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.cancel();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private static class MockDismissCancelHandler extends Handler {
+        private WeakReference<DialogInterface> mDialog;
+
+        public MockDismissCancelHandler(Dialog dialog, Looper looper) {
+            super(looper);
+
+            mDialog = new WeakReference<DialogInterface>(dialog);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case DISMISS:
+                ((OnDismissListener) msg.obj).onDismiss(mDialog.get());
+                break;
+            case CANCEL:
+                ((OnCancelListener) msg.obj).onCancel(mDialog.get());
+                break;
+            }
+        }
+    }
+
+    private static class MockDrawable extends Drawable {
+        @Override
+        public void draw(Canvas canvas) {
+        }
+
+        @Override
+        public int getOpacity() {
+            return 0;
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter cf) {
+        }
+    }
+
+    private static class MockView extends View {
+        public boolean isShowContextMenuCalled;
+        protected OnCreateContextMenuListener mOnCreateContextMenuListener;
+
+        public MockView(Context context) {
+            super(context);
+        }
+
+        public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) {
+            super.setOnCreateContextMenuListener(l);
+            mOnCreateContextMenuListener = l;
+        }
+
+        public OnCreateContextMenuListener getOnCreateContextMenuListener() {
+            return mOnCreateContextMenuListener;
+        }
+
+        @Override
+        public boolean showContextMenu() {
+            isShowContextMenuCalled = true;
+            return super.showContextMenu();
+        }
+    }
+}
diff --git a/tests/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/app/src/android/app/cts/DownloadManagerTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/cts/DownloadManagerTest.java
rename to tests/app/src/android/app/cts/DownloadManagerTest.java
diff --git a/tests/app/src/android/app/cts/ExpandableListActivityTest.java b/tests/app/src/android/app/cts/ExpandableListActivityTest.java
new file mode 100644
index 0000000..a457cf7
--- /dev/null
+++ b/tests/app/src/android/app/cts/ExpandableListActivityTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.stubs.ActivityTestsBase;
+import android.app.stubs.ExpandableListTestActivity;
+import android.app.stubs.LaunchpadActivity;
+import android.content.ComponentName;
+
+public class ExpandableListActivityTest extends ActivityTestsBase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mIntent.putExtra("component", new ComponentName(getContext(),
+                ExpandableListTestActivity.class));
+    }
+
+    public void testSelect() {
+        runLaunchpad(LaunchpadActivity.EXPANDLIST_SELECT);
+    }
+
+    public void testView() {
+        runLaunchpad(LaunchpadActivity.EXPANDLIST_VIEW);
+    }
+
+    public void testCallback() {
+        runLaunchpad(LaunchpadActivity.EXPANDLIST_CALLBACK);
+    }
+}
\ No newline at end of file
diff --git a/tests/app/src/android/app/cts/ExpandableListTestActivity.java b/tests/app/src/android/app/cts/ExpandableListTestActivity.java
deleted file mode 100644
index 8c8b65b..0000000
--- a/tests/app/src/android/app/cts/ExpandableListTestActivity.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.cts;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import android.app.ExpandableListActivity;
-import android.os.Bundle;
-import android.os.Looper;
-import android.os.MessageQueue;
-import android.view.ContextMenu;
-import android.view.View;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.widget.ExpandableListAdapter;
-import android.widget.ExpandableListView;
-import android.widget.SimpleExpandableListAdapter;
-
-import com.android.internal.R;
-import com.android.internal.view.menu.ContextMenuBuilder;
-import com.google.android.collect.Lists;
-
-public class ExpandableListTestActivity extends ExpandableListActivity {
-    private static final String NAME = "NAME";
-    private static final String IS_EVEN = "IS_EVEN";
-    private boolean mOnContentChangedCalled = false;
-    private boolean mOnCreateContextMenuCalled = false;
-    private boolean mOnGroupCollapseCalled = false;
-    private boolean mOnGroupExpandCalled = false;
-    private ExpandableListAdapter mAdapter;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        final List<Map<String, String>> groupData = Lists.newArrayList();
-        final List<List<Map<String, String>>> childData = Lists.newArrayList();
-        for (int i = 0; i < 20; i++) {
-            final Map<String, String> curGroupMap = new HashMap<String, String>();
-            groupData.add(curGroupMap);
-            curGroupMap.put(NAME, "Group " + i);
-            curGroupMap.put(IS_EVEN, (i % 2 == 0) ? "This group is even" : "This group is odd");
-
-            final List<Map<String, String>> children = Lists.newArrayList();
-            for (int j = 0; j < 15; j++) {
-                Map<String, String> curChildMap = new HashMap<String, String>();
-                children.add(curChildMap);
-                curChildMap.put(NAME, "Child " + j);
-                curChildMap.put(IS_EVEN, (j % 2 == 0) ? "This child is even" : "This child is odd");
-            }
-            childData.add(children);
-        }
-
-        // Set up our adapter
-        mAdapter = new SimpleExpandableListAdapter(this, groupData,
-                R.layout.simple_expandable_list_item_1,
-                new String[] { NAME, IS_EVEN }, new int[] { R.id.text1, R.id.text2 }, childData,
-                R.layout.simple_expandable_list_item_2,
-                new String[] { NAME, IS_EVEN }, new int[] { R.id.text1, R.id.text2 });
-        setListAdapter(mAdapter);
-
-    }
-
-    private int testCallback() {
-        final ExpandableListView v = getExpandableListView();
-        final ExpandableListAdapter a = getExpandableListAdapter();
-        final View convertView = new View(this);
-        final View gv = a.getGroupView(0, true, convertView, v);
-        v.setOnCreateContextMenuListener(this);
-        v.createContextMenu(new ContextMenuBuilder(this));
-        for (int i = 0; i < 20; i++) {
-            v.expandGroup(i);
-            v.performClick();
-            v.performLongClick();
-            for (int k = 0; k < 15; k++) {
-                v.performItemClick(gv, i, k);
-            }
-            v.collapseGroup(i);
-        }
-        if (mOnContentChangedCalled && mOnCreateContextMenuCalled
-                && mOnGroupCollapseCalled && mOnGroupExpandCalled)
-            return RESULT_OK;
-
-        return RESULT_CANCELED;
-    }
-
-    private int testView() {
-        final ExpandableListView currentView = getExpandableListView();
-        for (int i = 0; i < 20; i++) {
-            if (!currentView.expandGroup(i))
-                return RESULT_CANCELED;
-            if (!currentView.collapseGroup(i))
-                return RESULT_CANCELED;
-        }
-        final View otherView = findViewById(android.R.id.list);
-        setContentView(otherView);
-        if (!otherView.equals(getExpandableListView()))
-            return RESULT_CANCELED;
-        setContentView(currentView);
-        return RESULT_OK;
-    }
-
-    private int testSelecte() {
-        final ExpandableListView v = getExpandableListView();
-        for (int i = 0; i < 20; i++) {
-            v.expandGroup(i);
-            setSelectedGroup(i);
-            for (int k = 0; k < 15; k++) {
-                setSelectedChild(i, k, false);
-                if (ExpandableListView.getPackedPositionForChild(i, k) != getSelectedPosition())
-                    return RESULT_CANCELED;
-            }
-
-            for (int k = 0; k < 15; k++) {
-                setSelectedChild(i, k, true);
-                if (ExpandableListView.getPackedPositionForChild(i, k) != getSelectedPosition())
-                    return RESULT_CANCELED;
-            }
-            v.collapseGroup(i);
-        }
-        return RESULT_OK;
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        final String action = getIntent().getAction();
-        if (LaunchpadActivity.EXPANDLIST_SELECT.equals(action)) {
-            setResult(testSelecte());
-        } else if (LaunchpadActivity.EXPANDLIST_VIEW.equals(action)) {
-            setResult(testView());
-        } else if (LaunchpadActivity.EXPANDLIST_CALLBACK.equals(action)) {
-            setResult(testCallback());
-        }
-        Looper.myQueue().addIdleHandler(new Idler());
-    }
-
-    protected void onRestoreInstanceState(Bundle state) {
-        super.onRestoreInstanceState(state);
-    }
-
-    @Override
-    public void onContentChanged() {
-        mOnContentChangedCalled = true;
-        super.onContentChanged();
-    }
-
-    @Override
-    public void onCreateContextMenu(ContextMenu menu, View v,
-            ContextMenuInfo menuInfo) {
-        mOnCreateContextMenuCalled = true;
-        super.onCreateContextMenu(menu, v, menuInfo);
-    }
-
-    @Override
-    public void onGroupCollapse(int groupPosition) {
-        mOnGroupCollapseCalled = true;
-        super.onGroupCollapse(groupPosition);
-    }
-
-    @Override
-    public void onGroupExpand(int groupPosition) {
-        mOnGroupExpandCalled = true;
-        super.onGroupExpand(groupPosition);
-    }
-
-    protected void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-    }
-
-    protected void onStop() {
-        super.onStop();
-    }
-
-    private class Idler implements MessageQueue.IdleHandler {
-        public final boolean queueIdle() {
-            finish();
-            return false;
-        }
-    }
-
-}
diff --git a/tests/tests/app/src/android/app/cts/FragmentTest.java b/tests/app/src/android/app/cts/FragmentTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/cts/FragmentTest.java
rename to tests/app/src/android/app/cts/FragmentTest.java
diff --git a/tests/app/src/android/app/cts/FragmentTransitionTest.java b/tests/app/src/android/app/cts/FragmentTransitionTest.java
new file mode 100644
index 0000000..7270672
--- /dev/null
+++ b/tests/app/src/android/app/cts/FragmentTransitionTest.java
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.cts;
+
+import android.app.FragmentManager;
+import android.app.stubs.FragmentTestActivity;
+import android.app.stubs.FragmentTestActivity.OnTransitionListener;
+import android.app.stubs.FragmentTestActivity.TestFragment;
+import android.app.stubs.R;
+import android.os.Debug;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.View;
+
+public class FragmentTransitionTest extends
+        ActivityInstrumentationTestCase2<FragmentTestActivity> {
+    private TestFragment mStartFragment;
+    private TestFragment mMidFragment;
+    private TestFragment mEndFragment;
+    private FragmentTestActivity mActivity;
+
+    public FragmentTransitionTest() {
+        super(FragmentTestActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mStartFragment = null;
+        mMidFragment = null;
+        mEndFragment = null;
+        mActivity = getActivity();
+    }
+
+    public void testFragmentTransition() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mStartFragment = new TestFragment(R.layout.fragment_start);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mStartFragment)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mStartFragment, TestFragment.ENTER);
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
+        mStartFragment.clearNotifications();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final View sharedElement = mActivity.findViewById(R.id.hello);
+                assertEquals("source", sharedElement.getTransitionName());
+
+                mEndFragment = new TestFragment(R.layout.fragment_end);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mEndFragment)
+                        .addSharedElement(sharedElement, "destination")
+                        .addToBackStack(null)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mEndFragment, TestFragment.ENTER);
+        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
+        assertTrue(mEndFragment.wasEndCalled(TestFragment.SHARED_ELEMENT_ENTER));
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final View textView = mActivity.findViewById(R.id.hello);
+                assertEquals("destination", textView.getTransitionName());
+                mActivity.getFragmentManager().popBackStack();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mStartFragment, TestFragment.REENTER);
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.REENTER));
+        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
+    }
+
+    public void testFirstOutLastInTransition() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mStartFragment = new TestFragment(R.layout.fragment_start);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mStartFragment)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mStartFragment, TestFragment.ENTER);
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
+        mStartFragment.clearNotifications();
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mMidFragment = new TestFragment(R.layout.checkbox_layout);
+                mEndFragment = new TestFragment(R.layout.fragment_end);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mMidFragment)
+                        .replace(R.id.content, mEndFragment)
+                        .addToBackStack(null)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mEndFragment, TestFragment.ENTER);
+        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
+
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
+        assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
+        assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
+        assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
+
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+        mStartFragment.clearNotifications();
+        mEndFragment.clearNotifications();
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.getFragmentManager().popBackStack();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mEndFragment, TestFragment.RETURN);
+        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+        assertTrue(mStartFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
+    }
+
+    public void testPopTwo() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mStartFragment = new TestFragment(R.layout.fragment_start);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mStartFragment)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mStartFragment, TestFragment.ENTER);
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
+        mStartFragment.clearNotifications();
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mMidFragment = new TestFragment(R.layout.checkbox_layout);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mMidFragment)
+                        .addToBackStack(null)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mMidFragment, TestFragment.ENTER);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mEndFragment = new TestFragment(R.layout.fragment_end);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mEndFragment)
+                        .addToBackStack(null)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mEndFragment, TestFragment.ENTER);
+        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
+
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
+        assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
+        assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
+        assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
+
+        assertTrue(mMidFragment.wasStartCalled(TestFragment.ENTER));
+        assertTrue(mMidFragment.wasStartCalled(TestFragment.EXIT));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+        mStartFragment.clearNotifications();
+        mMidFragment.clearNotifications();
+        mEndFragment.clearNotifications();
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                FragmentManager fm = mActivity.getFragmentManager();
+                int id = fm.getBackStackEntryAt(0).getId();
+                fm.popBackStack(id, FragmentManager.POP_BACK_STACK_INCLUSIVE);
+                fm.executePendingTransactions();
+            }
+        });
+        waitForEnd(mEndFragment, TestFragment.RETURN);
+        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
+
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+        assertTrue(mStartFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
+    }
+
+    public void testNullTransition() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mStartFragment = new TestFragment(R.layout.fragment_start);
+                mStartFragment.clearTransitions();
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mStartFragment)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForStart(mStartFragment, TestFragment.ENTER);
+        // No transitions
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mMidFragment = new TestFragment(R.layout.checkbox_layout);
+                mEndFragment = new TestFragment(R.layout.fragment_end);
+                mEndFragment.clearTransitions();
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mMidFragment)
+                        .replace(R.id.content, mEndFragment)
+                        .addToBackStack(null)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForStart(mEndFragment, TestFragment.ENTER);
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.ENTER));
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
+
+        assertFalse(mStartFragment.wasEndCalled(TestFragment.EXIT));
+        assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
+        assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
+        assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
+
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.getFragmentManager().popBackStack();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForStart(mEndFragment, TestFragment.RETURN);
+        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
+    }
+
+    public void testRemoveAdded() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mStartFragment = new TestFragment(R.layout.fragment_start);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mStartFragment)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mStartFragment, TestFragment.ENTER);
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
+        mStartFragment.clearNotifications();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mEndFragment = new TestFragment(R.layout.fragment_end);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mEndFragment)
+                        .replace(R.id.content, mStartFragment)
+                        .replace(R.id.content, mEndFragment)
+                        .addToBackStack(null)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mEndFragment, TestFragment.ENTER);
+        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.getFragmentManager().popBackStack();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mStartFragment, TestFragment.REENTER);
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.REENTER));
+        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
+    }
+
+    public void testAddRemoved() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mStartFragment = new TestFragment(R.layout.fragment_start);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mStartFragment)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForEnd(mStartFragment, TestFragment.ENTER);
+        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
+        mStartFragment.clearNotifications();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mEndFragment = new TestFragment(R.layout.fragment_end);
+                mActivity.getFragmentManager().beginTransaction()
+                        .replace(R.id.content, mEndFragment)
+                        .replace(R.id.content, mStartFragment)
+                        .addToBackStack(null)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForStart(mStartFragment, TestFragment.ENTER);
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
+        assertFalse(mEndFragment.wasStartCalled(TestFragment.ENTER));
+        assertFalse(mEndFragment.wasStartCalled(TestFragment.EXIT));
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.getFragmentManager().popBackStack();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        waitForStart(mStartFragment, TestFragment.REENTER);
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
+        assertFalse(mEndFragment.wasStartCalled(TestFragment.REENTER));
+        assertFalse(mEndFragment.wasStartCalled(TestFragment.RETURN));
+    }
+
+    private boolean waitForStart(TestFragment fragment, int key) throws InterruptedException {
+        final boolean started;
+        WaitForTransition listener = new WaitForTransition(key, true);
+        fragment.setOnTransitionListener(listener);
+        final long endTime = SystemClock.uptimeMillis() + 100;
+        synchronized (listener) {
+            long waitTime;
+            while ((waitTime = endTime - SystemClock.uptimeMillis()) > 0 &&
+                    !listener.isDone()) {
+                listener.wait(waitTime);
+            }
+            started = listener.isDone();
+        }
+        fragment.setOnTransitionListener(null);
+        getInstrumentation().waitForIdleSync();
+        return started;
+    }
+
+    private boolean waitForEnd(TestFragment fragment, int key) throws InterruptedException {
+        if (!waitForStart(fragment, key)) {
+            return false;
+        }
+        final boolean ended;
+        WaitForTransition listener = new WaitForTransition(key, false);
+        fragment.setOnTransitionListener(listener);
+        final long endTime = SystemClock.uptimeMillis() + 400;
+        synchronized (listener) {
+            long waitTime;
+            while ((waitTime = endTime - SystemClock.uptimeMillis()) > 0 &&
+                    !listener.isDone()) {
+                listener.wait(waitTime);
+            }
+            ended = listener.isDone();
+        }
+        fragment.setOnTransitionListener(null);
+        getInstrumentation().waitForIdleSync();
+        return ended;
+    }
+
+    private static class WaitForTransition implements OnTransitionListener {
+        final int key;
+        final boolean isStart;
+        boolean isDone;
+
+        public WaitForTransition(int key, boolean isStart) {
+            this.key = key;
+            this.isStart = isStart;
+        }
+
+        protected boolean isComplete(TestFragment fragment) {
+            if (isStart) {
+                return fragment.wasStartCalled(key);
+            } else {
+                return fragment.wasEndCalled(key);
+            }
+        }
+
+        public synchronized boolean isDone() {
+            return isDone;
+        }
+
+        @Override
+        public synchronized void onTransition(TestFragment fragment) {
+            isDone = isComplete(fragment);
+            if (isDone) {
+                notifyAll();
+            }
+        }
+    }
+
+}
diff --git a/tests/app/src/android/app/cts/ISecondary.aidl b/tests/app/src/android/app/cts/ISecondary.aidl
deleted file mode 100644
index c3280d3..0000000
--- a/tests/app/src/android/app/cts/ISecondary.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-interface ISecondary {
-
-    int getPid();
-
-    long getElapsedCpuTime();
-
-    String getTimeZoneID();
-}
diff --git a/tests/app/src/android/app/cts/InstrumentationTest.java b/tests/app/src/android/app/cts/InstrumentationTest.java
new file mode 100644
index 0000000..5019586
--- /dev/null
+++ b/tests/app/src/android/app/cts/InstrumentationTest.java
@@ -0,0 +1,717 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.app.Instrumentation.ActivityResult;
+import android.app.stubs.InstrumentationTestActivity;
+import android.app.stubs.MockApplication;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.test.UiThreadTest;
+import android.view.InputQueue;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+
+import java.util.List;
+
+import android.app.stubs.R;
+
+public class InstrumentationTest extends InstrumentationTestCase {
+
+    private static final int WAIT_TIME = 1000;
+    private Instrumentation mInstrumentation;
+    private InstrumentationTestActivity mActivity;
+    private Intent mIntent;
+    private boolean mRunOnMainSyncResult;
+    private Context mContext;
+    private MockActivity mMockActivity;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mContext = mInstrumentation.getTargetContext();
+        mIntent = new Intent(mContext, InstrumentationTestActivity.class);
+        mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mActivity = (InstrumentationTestActivity) mInstrumentation.startActivitySync(mIntent);
+    }
+
+    protected void tearDown() throws Exception {
+        mInstrumentation = null;
+        mIntent = null;
+        if (mActivity != null) {
+            mActivity.finish();
+            mActivity = null;
+        }
+        super.tearDown();
+    }
+
+    public void testConstructor() throws Exception {
+        new Instrumentation();
+    }
+
+    public void testMonitor() throws Exception {
+        if (mActivity != null)
+            mActivity.finish();
+        ActivityResult result = new ActivityResult(Activity.RESULT_OK, new Intent());
+        ActivityMonitor monitor = new ActivityMonitor(
+                InstrumentationTestActivity.class.getName(), result, false);
+        mInstrumentation.addMonitor(monitor);
+        Intent intent = new Intent(mContext, InstrumentationTestActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(intent);
+        Activity activity = mInstrumentation.waitForMonitorWithTimeout(monitor, WAIT_TIME);
+        assertTrue(activity instanceof InstrumentationTestActivity);
+        assertTrue(mInstrumentation.checkMonitorHit(monitor, 1));
+        activity.finish();
+
+        mInstrumentation.addMonitor(monitor);
+        mInstrumentation.removeMonitor(monitor);
+        Activity a = mInstrumentation.startActivitySync(intent);
+        assertTrue(a instanceof InstrumentationTestActivity);
+        activity = mInstrumentation.waitForMonitorWithTimeout(monitor, WAIT_TIME);
+        assertNull(activity);
+        a.finish();
+
+        IntentFilter filter = new IntentFilter();
+        ActivityMonitor am = mInstrumentation.addMonitor(filter, result, false);
+        mContext.startActivity(intent);
+        mInstrumentation.waitForIdleSync();
+        activity = am.waitForActivity();
+        assertTrue(activity instanceof InstrumentationTestActivity);
+        activity.finish();
+        mInstrumentation.removeMonitor(am);
+        am = mInstrumentation
+                .addMonitor(InstrumentationTestActivity.class.getName(), result, false);
+        mContext.startActivity(intent);
+        activity = am.waitForActivity();
+        assertTrue(activity instanceof InstrumentationTestActivity);
+        activity.finish();
+        mInstrumentation.removeMonitor(am);
+    }
+
+    public void testCallActivityOnCreate() throws Throwable {
+        mActivity.setOnCreateCalled(false);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mInstrumentation.callActivityOnCreate(mActivity, new Bundle());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.isOnCreateCalled());
+    }
+
+    public void testAllocCounting() throws Exception {
+        mInstrumentation.startAllocCounting();
+
+        Bundle b = mInstrumentation.getAllocCounts();
+        assertTrue(b.size() > 0);
+        b = mInstrumentation.getBinderCounts();
+        assertTrue(b.size() > 0);
+
+        int globeAllocCount = Debug.getGlobalAllocCount();
+        int globeAllocSize = Debug.getGlobalAllocSize();
+        int globeExternalAllCount = Debug.getGlobalExternalAllocCount();
+        int globeExternalAllSize = Debug.getGlobalExternalAllocSize();
+        int threadAllocCount = Debug.getThreadAllocCount();
+
+        assertTrue(Debug.getGlobalAllocCount() >= globeAllocCount);
+        assertTrue(Debug.getGlobalAllocSize() >= globeAllocSize);
+        assertTrue(Debug.getGlobalExternalAllocCount() >= globeExternalAllCount);
+        assertTrue(Debug.getGlobalExternalAllocSize() >= globeExternalAllSize);
+        assertTrue(Debug.getThreadAllocCount() >= threadAllocCount);
+
+        mInstrumentation.stopAllocCounting();
+
+        globeAllocCount = Debug.getGlobalAllocCount();
+        globeAllocSize = Debug.getGlobalAllocSize();
+        globeExternalAllCount = Debug.getGlobalExternalAllocCount();
+        globeExternalAllSize = Debug.getGlobalExternalAllocSize();
+        threadAllocCount = Debug.getThreadAllocCount();
+        assertEquals(globeAllocCount, Debug.getGlobalAllocCount());
+        assertEquals(globeAllocSize, Debug.getGlobalAllocSize());
+        assertEquals(globeExternalAllCount, Debug.getGlobalExternalAllocCount());
+        assertEquals(globeExternalAllSize, Debug.getGlobalExternalAllocSize());
+        assertEquals(threadAllocCount, Debug.getThreadAllocCount());
+    }
+
+    public void testSendTrackballEventSync() throws Exception {
+        long now = SystemClock.uptimeMillis();
+        MotionEvent orig = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
+                100, 100, 0);
+        mInstrumentation.sendTrackballEventSync(orig);
+        mInstrumentation.waitForIdleSync();
+
+        MotionEvent motionEvent = mActivity.getMotionEvent();
+        assertEquals(orig.getMetaState(), motionEvent.getMetaState());
+        assertEquals(orig.getEventTime(), motionEvent.getEventTime());
+        assertEquals(orig.getDownTime(), motionEvent.getDownTime());
+    }
+
+    public void testCallApplicationOnCreate() throws Exception {
+        InstrumentationTestStub ca = new InstrumentationTestStub();
+        mInstrumentation.callApplicationOnCreate(ca);
+        assertTrue(ca.mIsOnCreateCalled);
+    }
+
+    public void testContext() throws Exception {
+        Context c1 = mInstrumentation.getContext();
+        Context c2 = mInstrumentation.getTargetContext();
+        assertNotSame(c1.getPackageName(), c2.getPackageName());
+    }
+
+    public void testInvokeMenuActionSync() throws Exception {
+        final int resId = R.id.goto_menu_id;
+        if (mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+            mInstrumentation.invokeMenuActionSync(mActivity, resId, 0);
+            mInstrumentation.waitForIdleSync();
+
+            assertEquals(resId, mActivity.getMenuID());
+        }
+    }
+
+    public void testCallActivityOnPostCreate() throws Throwable {
+        mActivity.setOnPostCreate(false);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mInstrumentation.callActivityOnPostCreate(mActivity, new Bundle());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.isOnPostCreate());
+    }
+
+    public void testCallActivityOnNewIntent() throws Throwable {
+        mActivity.setOnNewIntentCalled(false);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mInstrumentation.callActivityOnNewIntent(mActivity, null);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(mActivity.isOnNewIntentCalled());
+    }
+
+    public void testCallActivityOnResume() throws Throwable {
+        mActivity.setOnResume(false);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mInstrumentation.callActivityOnResume(mActivity);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.isOnResume());
+    }
+
+    public void testMisc() throws Exception {
+    }
+
+    public void testPerformanceSnapshot() throws Exception {
+        mInstrumentation.setAutomaticPerformanceSnapshots();
+        mInstrumentation.startPerformanceSnapshot();
+        mInstrumentation.endPerformanceSnapshot();
+    }
+
+    public void testProfiling() throws Exception {
+        // by default, profiling was disabled. but after set the handleProfiling attribute in the
+        // manifest file for this Instrumentation to true, the profiling was also disabled.
+        assertFalse(mInstrumentation.isProfiling());
+
+        mInstrumentation.startProfiling();
+        mInstrumentation.stopProfiling();
+    }
+
+    public void testInvokeContextMenuAction() throws Exception {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mMockActivity = new MockActivity();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final int id = 1;
+        final int flag = 2;
+        mInstrumentation.invokeContextMenuAction(mMockActivity, id, flag);
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(id, mMockActivity.mWindow.mId);
+        assertEquals(flag, mMockActivity.mWindow.mFlags);
+    }
+
+    public void testSendStringSync() {
+        final String text = "abcd";
+        mInstrumentation.sendStringSync(text);
+        mInstrumentation.waitForIdleSync();
+
+        List<KeyEvent> keyUpList = mActivity.getKeyUpList();
+        List<KeyEvent> keyDownList = mActivity.getKeyDownList();
+        assertEquals(text.length(), keyDownList.size());
+        assertEquals(text.length(), keyUpList.size());
+
+        KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+        KeyEvent[] keyEvents = kcm.getEvents(text.toCharArray());
+
+        int i = 0;
+        for (int j = 0; j < keyDownList.size(); j++) {
+            assertEquals(keyEvents[i++].getKeyCode(), keyDownList.get(j).getKeyCode());
+            assertEquals(keyEvents[i++].getKeyCode(), keyUpList.get(j).getKeyCode());
+        }
+    }
+
+    public void testCallActivityOnSaveInstanceState() throws Throwable {
+        final Bundle bundle = new Bundle();
+        mActivity.setOnSaveInstanceState(false);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mInstrumentation.callActivityOnSaveInstanceState(mActivity, bundle);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(mActivity.isOnSaveInstanceState());
+        assertSame(bundle, mActivity.getBundle());
+    }
+
+    public void testSendPointerSync() throws Exception {
+        mInstrumentation.waitForIdleSync();
+        mInstrumentation.setInTouchMode(true);
+
+        // Send a touch event to the middle of the activity.
+        // We assume that the Activity is empty so there won't be anything in the middle
+        // to handle the touch.  Consequently the Activity should receive onTouchEvent
+        // because nothing else handled it.
+        Point size = new Point();
+        mActivity.getWindowManager().getDefaultDisplay().getSize(size);
+        final int x = size.x / 2;
+        final int y = size.y / 2;
+        long now = SystemClock.uptimeMillis();
+        MotionEvent orig = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
+                x, y, 0);
+        mInstrumentation.sendPointerSync(orig);
+
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.isOnTouchEventCalled());
+        mActivity.setOnTouchEventCalled(false);
+    }
+
+    public void testGetComponentName() throws Exception {
+        ComponentName com = getInstrumentation().getComponentName();
+        assertNotNull(com.getPackageName());
+        assertNotNull(com.getClassName());
+        assertNotNull(com.getShortClassName());
+    }
+
+    public void testNewApplication() throws Exception {
+        final String className = "android.app.stubs.MockApplication";
+        ClassLoader cl = getClass().getClassLoader();
+
+        Application app = mInstrumentation.newApplication(cl, className, mContext);
+        assertEquals(className, app.getClass().getName());
+
+        app = Instrumentation.newApplication(MockApplication.class, mContext);
+        assertEquals(className, app.getClass().getName());
+    }
+
+    public void testRunOnMainSync() throws Exception {
+        mRunOnMainSyncResult = false;
+        mInstrumentation.runOnMainSync(new Runnable() {
+            public void run() {
+                mRunOnMainSyncResult = true;
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mRunOnMainSyncResult);
+    }
+
+    public void testCallActivityOnPause() throws Exception {
+        mActivity.setOnPauseCalled(false);
+        mInstrumentation.callActivityOnPause(mActivity);
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.isOnPauseCalled());
+    }
+
+    public void testSendKeyDownUpSync() throws Exception {
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
+        mInstrumentation.waitForIdleSync();
+        assertEquals(1, mActivity.getKeyUpList().size());
+        assertEquals(1, mActivity.getKeyDownList().size());
+        assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyUpList().get(0).getKeyCode());
+        assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyDownList().get(0).getKeyCode());
+    }
+
+    @UiThreadTest
+    public void testNewActivity() throws Exception {
+        Intent intent = new Intent();
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        ClassLoader cl = getClass().getClassLoader();
+        Activity activity = mInstrumentation.newActivity(cl, InstrumentationTestActivity.class
+                .getName(), intent);
+        assertEquals(InstrumentationTestActivity.class.getName(), activity.getClass().getName());
+        activity.finish();
+        activity = null;
+
+        intent = new Intent(mContext, InstrumentationTestActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        Activity father = new Activity();
+        ActivityInfo info = new ActivityInfo();
+
+        activity = mInstrumentation
+                .newActivity(InstrumentationTestActivity.class, mContext, null, null, intent, info,
+                        InstrumentationTestActivity.class.getName(), father, null, null);
+
+        assertEquals(father, activity.getParent());
+        assertEquals(InstrumentationTestActivity.class.getName(), activity.getClass().getName());
+        activity.finish();
+    }
+
+    public void testCallActivityOnStart() throws Exception {
+        mActivity.setOnStart(false);
+        mInstrumentation.callActivityOnStart(mActivity);
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.isOnStart());
+    }
+
+    public void testWaitForIdle() throws Exception {
+        MockRunnable mr = new MockRunnable();
+        assertFalse(mr.isRunCalled());
+        mInstrumentation.waitForIdle(mr);
+        Thread.sleep(WAIT_TIME);
+        assertTrue(mr.isRunCalled());
+    }
+
+    public void testSendCharacterSync() throws Exception {
+        mInstrumentation.sendCharacterSync(KeyEvent.KEYCODE_0);
+        mInstrumentation.waitForIdleSync();
+        assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyDownCode());
+        assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyUpCode());
+    }
+
+    public void testCallActivityOnRestart() throws Exception {
+        mActivity.setOnRestart(false);
+        mInstrumentation.callActivityOnRestart(mActivity);
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.isOnRestart());
+    }
+
+    public void testCallActivityOnStop() throws Exception {
+        mActivity.setOnStop(false);
+        mInstrumentation.callActivityOnStop(mActivity);
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.isOnStop());
+    }
+
+    public void testCallActivityOnUserLeaving() throws Exception {
+        assertFalse(mActivity.isOnLeave());
+        mInstrumentation.callActivityOnUserLeaving(mActivity);
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.isOnLeave());
+    }
+
+    public void testCallActivityOnRestoreInstanceState() throws Exception {
+        mActivity.setOnRestoreInstanceState(false);
+        mInstrumentation.callActivityOnRestoreInstanceState(mActivity, new Bundle());
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActivity.isOnRestoreInstanceState());
+    }
+
+    public void testSendKeySync() throws Exception {
+        KeyEvent key = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
+        mInstrumentation.sendKeySync(key);
+        mInstrumentation.waitForIdleSync();
+        assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyDownCode());
+    }
+
+    private static class MockRunnable implements Runnable {
+        private boolean mIsRunCalled ;
+
+        public void run() {
+            mIsRunCalled = true;
+        }
+
+        public boolean isRunCalled() {
+            return mIsRunCalled;
+        }
+    }
+
+    private class MockActivity extends Activity {
+        MockWindow mWindow = new MockWindow(mContext);
+
+        @Override
+        public Window getWindow() {
+            return mWindow;
+        }
+
+        private class MockWindow extends Window {
+
+            public int mId;
+            public int mFlags;
+
+            public MockWindow(Context context) {
+                super(context);
+            }
+
+            @Override
+            public void addContentView(View view, LayoutParams params) {
+            }
+
+            @Override
+            public void closeAllPanels() {
+            }
+
+            @Override
+            public void closePanel(int featureId) {
+            }
+
+            @Override
+            public View getCurrentFocus() {
+                return null;
+            }
+
+            @Override
+            public View getDecorView() {
+                return null;
+            }
+
+            @Override
+            public LayoutInflater getLayoutInflater() {
+                return null;
+            }
+
+            @Override
+            public int getVolumeControlStream() {
+                return 0;
+            }
+
+            @Override
+            public boolean isFloating() {
+                return false;
+            }
+
+            @Override
+            public boolean isShortcutKey(int keyCode, KeyEvent event) {
+                return false;
+            }
+
+            @Override
+            protected void onActive() {
+            }
+
+            @Override
+            public void onConfigurationChanged(Configuration newConfig) {
+            }
+
+            @Override
+            public void openPanel(int featureId, KeyEvent event) {
+            }
+
+            public void alwaysReadCloseOnTouchAttr() {
+            }
+
+            @Override
+            public View peekDecorView() {
+                return null;
+            }
+
+            @Override
+            public boolean performContextMenuIdentifierAction(int id, int flags) {
+                mId = id;
+                mFlags = flags;
+                return false;
+            }
+
+            @Override
+            public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
+                return false;
+            }
+
+            @Override
+            public boolean performPanelShortcut(int featureId, int keyCode,
+                    KeyEvent event, int flags) {
+                return false;
+            }
+
+            @Override
+            public void restoreHierarchyState(Bundle savedInstanceState) {
+            }
+
+            @Override
+            public Bundle saveHierarchyState() {
+                return null;
+            }
+
+            @Override
+            public void setBackgroundDrawable(Drawable drawable) {
+            }
+
+            @Override
+            public void setChildDrawable(int featureId, Drawable drawable) {
+            }
+
+            @Override
+            public void setChildInt(int featureId, int value) {
+            }
+
+            @Override
+            public void setContentView(int layoutResID) {
+            }
+
+            @Override
+            public void setContentView(View view) {
+            }
+
+            @Override
+            public void setContentView(View view, LayoutParams params) {
+            }
+
+            @Override
+            public void setFeatureDrawable(int featureId, Drawable drawable) {
+            }
+
+            @Override
+            public void setFeatureDrawableAlpha(int featureId, int alpha) {
+            }
+
+            @Override
+            public void setFeatureDrawableResource(int featureId, int resId) {
+            }
+
+            @Override
+            public void setFeatureDrawableUri(int featureId, Uri uri) {
+            }
+
+            @Override
+            public void setFeatureInt(int featureId, int value) {
+            }
+
+            @Override
+            public void setTitle(CharSequence title) {
+            }
+
+            @Override
+            public void setTitleColor(int textColor) {
+            }
+
+            @Override
+            public void setVolumeControlStream(int streamType) {
+            }
+
+            @Override
+            public boolean superDispatchKeyEvent(KeyEvent event) {
+                return false;
+            }
+
+            @Override
+            public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
+                return false;
+            }
+
+            @Override
+            public boolean superDispatchTouchEvent(MotionEvent event) {
+                return false;
+            }
+
+            @Override
+            public boolean superDispatchTrackballEvent(MotionEvent event) {
+                return false;
+            }
+
+            @Override
+            public boolean superDispatchGenericMotionEvent(MotionEvent event) {
+                return false;
+            }
+
+            @Override
+            public void takeKeyEvents(boolean get) {
+            }
+
+            @Override
+            public void togglePanel(int featureId, KeyEvent event) {
+            }
+
+            @Override
+            public void invalidatePanelMenu(int featureId) {
+            }
+
+            @Override
+            public void takeSurface(SurfaceHolder.Callback2 callback) {
+            }
+
+            @Override
+            public void takeInputQueue(InputQueue.Callback queue) {
+            }
+
+            @Override
+            public void setStatusBarColor(int color) {
+            }
+
+            @Override
+            public int getStatusBarColor() {
+                return 0;
+            }
+
+            @Override
+            public void setNavigationBarColor(int color) {
+            }
+
+            @Override
+            public void setDecorCaptionShade(int decorCaptionShade) {
+            }
+
+            @Override
+            public void setResizingCaptionDrawable(Drawable drawable) {
+            }
+
+            @Override
+            public int getNavigationBarColor() {
+                return 0;
+            }
+        }
+    }
+
+    private static class InstrumentationTestStub extends Application {
+        boolean mIsOnCreateCalled = false;
+
+        @Override
+        public void onCreate() {
+            super.onCreate();
+            mIsOnCreateCalled = true;
+        }
+    }
+}
diff --git a/tests/app/src/android/app/cts/InstrumentationTestActivity.java b/tests/app/src/android/app/cts/InstrumentationTestActivity.java
deleted file mode 100644
index bec721e..0000000
--- a/tests/app/src/android/app/cts/InstrumentationTestActivity.java
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import java.util.ArrayList;
-import java.util.List;
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.TextView;
-import com.android.cts.app.stub.R;
-
-public class InstrumentationTestActivity extends Activity {
-
-    private boolean mOnCreateCalled;
-    private boolean mOnDestroyCalled ;
-    private boolean mOnNewIntentCalled;
-    private boolean mOnPauseCalled;
-    private boolean mOnPostCreate;
-    private boolean mOnRestart;
-    private boolean mOnRestoreInstanceState;
-    private boolean mOnResume;
-    private boolean mOnSaveInstanceState;
-    private boolean mOnStart;
-    private boolean mOnStop;
-    private boolean mOnMenuOpened;
-    private boolean mOnLeave;
-    private int mMenuID;
-    private boolean mOnTouchEventCalled;
-    private int mKeyDownCode;
-    private int mKeyUpCode;
-    private MotionEvent mMotionEvent;
-    private Bundle mBundle;
-    private MockTextView mTextView;
-    private List<KeyEvent> mKeyDownList = new ArrayList<KeyEvent>();
-    private List<KeyEvent> mKeyUpList = new ArrayList<KeyEvent>();
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mTextView = new MockTextView(this);
-        setContentView(mTextView);
-        mOnCreateCalled = true;
-    }
-
-    class MockTextView extends TextView {
-
-        public MockTextView(Context context) {
-            super(context);
-        }
-
-        @Override
-        public boolean onTouchEvent(MotionEvent event) {
-            return super.onTouchEvent(event);
-        }
-
-        @Override
-        public boolean onTrackballEvent(MotionEvent event) {
-            return super.onTrackballEvent(event);
-        }
-
-        @Override
-        public void getLocationOnScreen(int[] location) {
-            super.getLocationOnScreen(location);
-            location[0] = location[1] = 10;
-        }
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        mOnDestroyCalled = true;
-    }
-
-    @Override
-    protected void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-        mOnNewIntentCalled = true;
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        mOnPauseCalled = true;
-    }
-
-    @Override
-    protected void onPostCreate(Bundle savedInstanceState) {
-        super.onPostCreate(savedInstanceState);
-        mOnPostCreate = true;
-    }
-
-    @Override
-    protected void onRestart() {
-        super.onRestart();
-        mOnRestart = true;
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Bundle savedInstanceState) {
-        super.onRestoreInstanceState(savedInstanceState);
-        mOnRestoreInstanceState = true;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        mOnTouchEventCalled = true;
-        mMotionEvent = event;
-        return super.onTouchEvent(event);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        mOnResume = true;
-    }
-
-    @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        mOnSaveInstanceState = true;
-        mBundle = outState;
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-        mOnStart = true;
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        mOnStop = true;
-    }
-
-    @Override
-    protected void onUserLeaveHint() {
-        super.onUserLeaveHint();
-        mOnLeave = true;
-    }
-
-    @Override
-    public boolean onMenuOpened(int featureId, Menu menu) {
-        mOnMenuOpened = true;
-        return super.onMenuOpened(featureId, menu);
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        super.onCreateOptionsMenu(menu);
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.browser, menu);
-
-        menu.add("title");
-        mOnMenuOpened = true;
-        return true;
-    }
-
-    @Override
-    public boolean onCreatePanelMenu(int featureId, Menu menu) {
-        return super.onCreatePanelMenu(featureId, menu);
-    }
-
-    @Override
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {
-        mMenuID = item.getItemId();
-        return super.onMenuItemSelected(featureId, item);
-    }
-
-    @Override
-    public void openContextMenu(View view) {
-        super.openContextMenu(view);
-    }
-
-    @Override
-    public void openOptionsMenu() {
-        super.openOptionsMenu();
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        return super.onOptionsItemSelected(item);
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        mKeyDownList.add(event);
-        mKeyDownCode = keyCode;
-        return super.onKeyDown(keyCode, event);
-    }
-
-    @Override
-    public boolean onTrackballEvent(MotionEvent event) {
-        mMotionEvent = event;
-        return super.onTrackballEvent(event);
-    }
-
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        mKeyUpList.add(event);
-        mKeyUpCode = keyCode;
-        return super.onKeyUp(keyCode, event);
-    }
-
-    public boolean isOnCreateCalled() {
-        return mOnCreateCalled;
-    }
-
-    public void setOnCreateCalled(boolean onCreateCalled) {
-        mOnCreateCalled = onCreateCalled;
-    }
-
-    public boolean isOnDestroyCalled() {
-        return mOnDestroyCalled;
-    }
-
-    public void setOnDestroyCalled(boolean onDestroyCalled) {
-        mOnDestroyCalled = onDestroyCalled;
-    }
-
-    public boolean isOnNewIntentCalled() {
-        return mOnNewIntentCalled;
-    }
-
-    public void setOnNewIntentCalled(boolean onNewIntentCalled) {
-        mOnNewIntentCalled = onNewIntentCalled;
-    }
-
-    public boolean isOnPauseCalled() {
-        return mOnPauseCalled;
-    }
-
-    public void setOnPauseCalled(boolean onPauseCalled) {
-        mOnPauseCalled = onPauseCalled;
-    }
-
-    public boolean isOnPostCreate() {
-        return mOnPostCreate;
-    }
-
-    public void setOnPostCreate(boolean onPostCreate) {
-        mOnPostCreate = onPostCreate;
-    }
-
-    public boolean isOnRestart() {
-        return mOnRestart;
-    }
-
-    public void setOnRestart(boolean onRestart) {
-        mOnRestart = onRestart;
-    }
-
-    public boolean isOnRestoreInstanceState() {
-        return mOnRestoreInstanceState;
-    }
-
-    public void setOnRestoreInstanceState(boolean onRestoreInstanceState) {
-        mOnRestoreInstanceState = onRestoreInstanceState;
-    }
-
-    public boolean isOnResume() {
-        return mOnResume;
-    }
-
-    public void setOnResume(boolean onResume) {
-        mOnResume = onResume;
-    }
-
-    public boolean isOnSaveInstanceState() {
-        return mOnSaveInstanceState;
-    }
-
-    public void setOnSaveInstanceState(boolean onSaveInstanceState) {
-        mOnSaveInstanceState = onSaveInstanceState;
-    }
-
-    public boolean isOnStart() {
-        return mOnStart;
-    }
-
-    public void setOnStart(boolean onStart) {
-        mOnStart = onStart;
-    }
-
-    public boolean isOnStop() {
-        return mOnStop;
-    }
-
-    public boolean isOnLeave() {
-        return mOnLeave;
-    }
-
-    public void setOnStop(boolean onStop) {
-        mOnStop = onStop;
-    }
-
-    public boolean isMOnMenuOpened() {
-        return mOnMenuOpened;
-    }
-
-    public void setOnMenuOpened(boolean onMenuOpened) {
-        mOnMenuOpened = onMenuOpened;
-    }
-
-    public int getMenuID() {
-        return mMenuID;
-    }
-
-    public void setMenuID(int menuID) {
-        mMenuID = menuID;
-    }
-
-    public MotionEvent getMotionEvent() {
-        return mMotionEvent;
-    }
-
-    public Bundle getBundle() {
-        return mBundle;
-    }
-
-    public boolean isOnTouchEventCalled() {
-        return mOnTouchEventCalled;
-    }
-
-    public void setOnTouchEventCalled(boolean onTouchEventCalled) {
-        mOnTouchEventCalled = onTouchEventCalled;
-    }
-
-    public int getKeyUpCode() {
-        return mKeyUpCode;
-    }
-
-    public int getKeyDownCode() {
-        return mKeyDownCode;
-    }
-
-    public List<KeyEvent> getKeyUpList() {
-        return mKeyUpList;
-    }
-
-    public List<KeyEvent> getKeyDownList() {
-        return mKeyDownList;
-    }
-}
diff --git a/tests/app/src/android/app/cts/Instrumentation_ActivityMonitorTest.java b/tests/app/src/android/app/cts/Instrumentation_ActivityMonitorTest.java
new file mode 100644
index 0000000..719f74b
--- /dev/null
+++ b/tests/app/src/android/app/cts/Instrumentation_ActivityMonitorTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.app.Instrumentation.ActivityResult;
+import android.app.stubs.InstrumentationTestActivity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.test.InstrumentationTestCase;
+
+public class Instrumentation_ActivityMonitorTest extends InstrumentationTestCase {
+
+    private static final long WAIT_TIMEOUT = 100;
+
+    /**
+     * check points:
+     * 1 Constructor with blocking true and false
+     * 2 waitForActivity with timeout and no timeout
+     * 3 get info about ActivityMonitor
+     */
+    public void testActivityMonitor() throws Exception {
+        ActivityResult result = new ActivityResult(Activity.RESULT_OK, new Intent());
+        Instrumentation instrumentation = getInstrumentation();
+        ActivityMonitor am = instrumentation.addMonitor(
+                InstrumentationTestActivity.class.getName(), result, false);
+        Context context = instrumentation.getTargetContext();
+        Intent intent = new Intent(context, InstrumentationTestActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+        Activity lastActivity = am.getLastActivity();
+        final long TIMEOUT_MSEC = 5000;
+        long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
+        while (lastActivity == null && System.currentTimeMillis() < timeout) {
+            Thread.sleep(WAIT_TIMEOUT);
+            lastActivity = am.getLastActivity();
+        }
+        Activity activity = am.waitForActivity();
+        assertSame(activity, lastActivity);
+        assertEquals(1, am.getHits());
+        assertTrue(activity instanceof InstrumentationTestActivity);
+        activity.finish();
+        instrumentation.waitForIdleSync();
+        context.startActivity(intent);
+        timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
+        activity = null;
+        while (activity == null && System.currentTimeMillis() < timeout) {
+            Thread.sleep(WAIT_TIMEOUT);
+            activity = am.waitForActivityWithTimeout(WAIT_TIMEOUT);
+        }
+        assertNotNull(activity);
+        activity.finish();
+        instrumentation.removeMonitor(am);
+
+        am = new ActivityMonitor(InstrumentationTestActivity.class.getName(), result, true);
+        assertSame(result, am.getResult());
+        assertTrue(am.isBlocking());
+        IntentFilter which = new IntentFilter();
+        am = new ActivityMonitor(which, result, false);
+        assertSame(which, am.getFilter());
+        assertFalse(am.isBlocking());
+    }
+}
diff --git a/tests/tests/app/src/android/app/cts/Instrumentation_ActivityResultTest.java b/tests/app/src/android/app/cts/Instrumentation_ActivityResultTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/cts/Instrumentation_ActivityResultTest.java
rename to tests/app/src/android/app/cts/Instrumentation_ActivityResultTest.java
diff --git a/tests/app/src/android/app/cts/IntentServiceStub.java b/tests/app/src/android/app/cts/IntentServiceStub.java
deleted file mode 100644
index 8f23a4f..0000000
--- a/tests/app/src/android/app/cts/IntentServiceStub.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.IntentService;
-import android.content.Intent;
-import android.cts.util.PollingCheck;
-import android.os.Binder;
-import android.os.IBinder;
-
-public class IntentServiceStub extends IntentService {
-    public IntentServiceStub() {
-        super("IntentServiceStub");
-    }
-
-    public static final String ISS_ADD = "add";
-    public static final String ISS_VALUE = "value";
-
-    private static int onHandleIntentCalled;
-    private static boolean onBindCalled;
-    private static boolean onCreateCalled;
-    private static boolean onDestroyCalled;
-    private static boolean onStartCalled;
-    private static int accumulator;
-
-    private static Throwable throwable;
-
-    public synchronized static void reset() {
-        onHandleIntentCalled = 0;
-        onBindCalled = false;
-        onCreateCalled = false;
-        onDestroyCalled = false;
-        onStartCalled = false;
-        accumulator = 0;
-        throwable = null;
-    }
-
-    public static void waitToFinish(long timeout) throws Throwable {
-        new PollingCheck(timeout) {
-            @Override
-            protected boolean check() {
-                synchronized (IntentServiceStub.class) {
-                    return IntentServiceStub.onDestroyCalled;
-                }
-            }
-        }.run();
-        if (throwable != null) {
-            throw throwable;
-        }
-    }
-
-    @Override
-    protected void onHandleIntent(Intent intent) {
-        synchronized (IntentServiceStub.class) {
-            onHandleIntentCalled += 1;
-            try {
-                String action = intent.getAction();
-                if (action != null && action.equals(ISS_ADD)) {
-                    accumulator += intent.getIntExtra(ISS_VALUE, 0);
-                }
-            } catch (Throwable t) {
-                throwable = t;
-            }
-        }
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        synchronized (IntentServiceStub.class) {
-            onBindCalled = true;
-        }
-        return new Binder();
-    }
-
-    @Override
-    public void onCreate() {
-        synchronized (IntentServiceStub.class) {
-            onCreateCalled = true;
-        }
-        super.onCreate();
-    }
-
-    @Override
-    public void onDestroy() {
-        synchronized (IntentServiceStub.class) {
-            onDestroyCalled = true;
-        }
-        super.onDestroy();
-    }
-
-    @Override
-    public void onStart(Intent intent, int startId) {
-        synchronized (IntentService.class) {
-            onStartCalled = true;
-        }
-        super.onStart(intent, startId);
-    }
-
-    public synchronized static int getOnHandleIntentCalledCount() {
-        return onHandleIntentCalled;
-    }
-
-    public synchronized static boolean isOnBindCalled() {
-        return onBindCalled;
-    }
-
-    public synchronized static boolean isOnCreateCalled() {
-        return onCreateCalled;
-    }
-
-    public synchronized static boolean isOnDestroyCalled() {
-        return onDestroyCalled;
-    }
-
-    public synchronized static boolean isOnStartCalled() {
-        return onStartCalled;
-    }
-
-    public synchronized static int getAccumulator() {
-        return accumulator;
-    }
-}
diff --git a/tests/app/src/android/app/cts/IntentServiceTest.java b/tests/app/src/android/app/cts/IntentServiceTest.java
new file mode 100644
index 0000000..9d721fe
--- /dev/null
+++ b/tests/app/src/android/app/cts/IntentServiceTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.stubs.ActivityTestsBase;
+import android.app.stubs.IntentServiceStub;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.cts.util.PollingCheck;
+import android.os.IBinder;
+
+import java.util.concurrent.Callable;
+
+public class IntentServiceTest extends ActivityTestsBase {
+
+    private Intent mIntent;
+    private static final int TIMEOUT_MSEC = 30000;
+    private boolean mConnected;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        IntentServiceStub.reset();
+        mIntent = new Intent(mContext, IntentServiceStub.class);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mContext.stopService(mIntent);
+    }
+
+    public void testIntents() throws Throwable {
+        final int value = 42;
+        final int adds = 3;
+
+        Intent addIntent = new Intent(mContext, IntentServiceStub.class);
+
+        addIntent.setAction(IntentServiceStub.ISS_ADD);
+        addIntent.putExtra(IntentServiceStub.ISS_VALUE, 42);
+
+        for (int i = 0; i < adds; i++) {
+            mContext.startService(addIntent);
+        }
+
+        PollingCheck.check("onHandleIntentCalled not called enough", TIMEOUT_MSEC,
+                new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return IntentServiceStub.getOnHandleIntentCalledCount() == adds;
+            }
+        });
+
+        PollingCheck.check("accumulator not correct", TIMEOUT_MSEC, new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return IntentServiceStub.getAccumulator() == adds * value;
+            }
+        });
+
+        PollingCheck.check("onDestroyCalled not called", TIMEOUT_MSEC, new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return IntentServiceStub.isOnDestroyCalled();
+            }
+        });
+    }
+
+    public void testIntentServiceLifeCycle() throws Throwable {
+        // start service
+        mContext.startService(mIntent);
+        new PollingCheck(TIMEOUT_MSEC) {
+            protected boolean check() {
+                return IntentServiceStub.getOnHandleIntentCalledCount() > 0;
+            }
+        }.run();
+        assertTrue(IntentServiceStub.isOnCreateCalled());
+        assertTrue(IntentServiceStub.isOnStartCalled());
+
+        // bind service
+        ServiceConnection conn = new TestConnection();
+        mContext.bindService(mIntent, conn, Context.BIND_AUTO_CREATE);
+        new PollingCheck(TIMEOUT_MSEC) {
+            protected boolean check() {
+                return mConnected;
+            }
+        }.run();
+        assertTrue(IntentServiceStub.isOnBindCalled());
+
+        // unbind service
+        mContext.unbindService(conn);
+        // stop service
+        mContext.stopService(mIntent);
+        IntentServiceStub.waitToFinish(TIMEOUT_MSEC);
+    }
+
+    private class TestConnection implements ServiceConnection {
+
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mConnected = true;
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    }
+}
diff --git a/tests/app/src/android/app/cts/KeyguardManagerActivity.java b/tests/app/src/android/app/cts/KeyguardManagerActivity.java
deleted file mode 100644
index a1f5289..0000000
--- a/tests/app/src/android/app/cts/KeyguardManagerActivity.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.cts;
-
-import android.app.Activity;
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.KeyEvent;
-
-public class KeyguardManagerActivity extends Activity {
-    private static final String TAG = "KeyguardManagerActivity";
-    public static final boolean DEBUG = false;
-    private KeyguardManager mKeyguardManager;
-    private KeyguardManager.KeyguardLock mKeyLock;
-    public int keyCode;
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
-        mKeyLock = null;
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        if (DEBUG) {
-            Log.d(TAG, "onResume");
-        }
-        if (mKeyLock == null) {
-            mKeyLock = mKeyguardManager.newKeyguardLock(TAG);
-            mKeyLock.disableKeyguard();
-            if (DEBUG) {
-                Log.d(TAG, "disableKeyguard");
-            }
-        }
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        this.keyCode = keyCode;
-        if (keyCode == KeyEvent.KEYCODE_0 && mKeyLock != null) {
-            mKeyLock.reenableKeyguard();
-            mKeyLock = null;
-            if (DEBUG) {
-                Log.d(TAG, "reenableKeyguard");
-            }
-        }
-        if (DEBUG) {
-            Log.d(TAG, "onKeyDown");
-        }
-        return super.onKeyDown(keyCode, event);
-    }
-}
diff --git a/tests/app/src/android/app/cts/KeyguardManagerKeyguardLockTest.java b/tests/app/src/android/app/cts/KeyguardManagerKeyguardLockTest.java
new file mode 100644
index 0000000..33d42ce
--- /dev/null
+++ b/tests/app/src/android/app/cts/KeyguardManagerKeyguardLockTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.test.InstrumentationTestCase;
+
+public class KeyguardManagerKeyguardLockTest extends InstrumentationTestCase {
+
+    public void testDisableKeyguard() {
+    }
+
+    public void testReenableKeyguard() {
+    }
+}
diff --git a/tests/app/src/android/app/cts/KeyguardManagerTest.java b/tests/app/src/android/app/cts/KeyguardManagerTest.java
new file mode 100644
index 0000000..23410ed5
--- /dev/null
+++ b/tests/app/src/android/app/cts/KeyguardManagerTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.KeyguardManager;
+import android.app.stubs.KeyguardManagerActivity;
+import android.content.Context;
+import android.test.ActivityInstrumentationTestCase2;
+
+public class KeyguardManagerTest
+        extends ActivityInstrumentationTestCase2<KeyguardManagerActivity> {
+
+    private static final String TAG = "KeyguardManagerTest";
+
+    public KeyguardManagerTest() {
+        super("android.app.stubs", KeyguardManagerActivity.class);
+    }
+
+    public void testNewKeyguardLock() {
+        final Context c = getInstrumentation().getContext();
+        final KeyguardManager keyguardManager = (KeyguardManager) c.getSystemService(
+                Context.KEYGUARD_SERVICE);
+        final KeyguardManager.KeyguardLock keyLock = keyguardManager.newKeyguardLock(TAG);
+        assertNotNull(keyLock);
+    }
+
+    public void testInKeyguardRestrictedInputMode() {
+    }
+
+    public void testExitKeyguardSecurely() {
+    }
+}
diff --git a/tests/app/src/android/app/cts/LaunchTest.java b/tests/app/src/android/app/cts/LaunchTest.java
new file mode 100644
index 0000000..eaa4b2f
--- /dev/null
+++ b/tests/app/src/android/app/cts/LaunchTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.stubs.ActivityTestsBase;
+import android.app.stubs.ClearTop;
+import android.app.stubs.LaunchpadActivity;
+import android.app.stubs.LocalActivity;
+import android.app.stubs.LocalScreen;
+import android.app.stubs.TestedActivity;
+import android.app.stubs.TestedScreen;
+import android.content.ComponentName;
+
+public class LaunchTest extends ActivityTestsBase {
+
+    public void testClearTopWhilResumed() {
+        mIntent.putExtra("component", new ComponentName(getContext(), ClearTop.class));
+        mIntent.putExtra(ClearTop.WAIT_CLEAR_TASK, true);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testClearTopInCreate() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), ClearTop.class));
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testForwardResult() {
+        runLaunchpad(LaunchpadActivity.FORWARD_RESULT);
+    }
+
+    public void testLocalScreen() {
+        mIntent.putExtra("component", new ComponentName(getContext(), LocalScreen.class));
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testColdScreen() {
+        mIntent.putExtra("component", new ComponentName(getContext(), TestedScreen.class));
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testLocalActivity() {
+        mIntent.putExtra("component", new ComponentName(getContext(), LocalActivity.class));
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testColdActivity() {
+        mIntent.putExtra("component", new ComponentName(getContext(), TestedActivity.class));
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+}
diff --git a/tests/app/src/android/app/cts/LauncherActivityStub.java b/tests/app/src/android/app/cts/LauncherActivityStub.java
deleted file mode 100644
index 4be63d6..0000000
--- a/tests/app/src/android/app/cts/LauncherActivityStub.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.LauncherActivity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ListView;
-
-public class LauncherActivityStub extends LauncherActivity {
-    public boolean isOnCreateCalled = false;
-    public boolean isOnListItemClick = false;
-    // For testing LauncherActivity#getTargetIntent()
-    private Intent mSuperIntent;
-
-    public Intent getSuperIntent() {
-        return mSuperIntent;
-    }
-
-    @Override
-    protected Intent getTargetIntent() {
-        mSuperIntent = super.getTargetIntent();
-        Intent targetIntent = new Intent(Intent.ACTION_MAIN, null);
-        targetIntent.addCategory(Intent.CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST);
-        targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        return targetIntent;
-    }
-
-    @Override
-    protected Intent intentForPosition(int position) {
-        return super.intentForPosition(position);
-    }
-
-    public LauncherActivityStub() {
-        super();
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        isOnCreateCalled = true;
-    }
-
-    @Override
-    public void onListItemClick(ListView l, View v, int position, long id) {
-        super.onListItemClick(l, v, position, id);
-        isOnListItemClick = true;
-    }
-}
diff --git a/tests/app/src/android/app/cts/LauncherActivityTest.java b/tests/app/src/android/app/cts/LauncherActivityTest.java
new file mode 100644
index 0000000..6ab4608
--- /dev/null
+++ b/tests/app/src/android/app/cts/LauncherActivityTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Instrumentation;
+import android.app.LauncherActivity.ListItem;
+import android.app.stubs.LauncherActivityStub;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+
+import java.util.List;
+
+public class LauncherActivityTest
+        extends ActivityInstrumentationTestCase2<LauncherActivityStub> {
+
+    private Instrumentation mInstrumentation;
+    private LauncherActivityStub mActivity;
+
+    public LauncherActivityTest() {
+        super("android.app.stubs", LauncherActivityStub.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+    }
+
+    public void testLaunchActivity() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                // Test getTargetIntent. LaunchActivity#getTargetIntent() just returns a Intent() instance
+                // with no content, so we use LaunchActivityStub#getSuperIntent() to get the default Intent,
+                // and create a new intent for other tests.
+                assertNotNull(mActivity.getSuperIntent());
+
+                // Test makeListItems. Make sure the size > 0. The sorted order is related to the sort
+                // way, so it's mutable.
+                final List<ListItem> list = mActivity.makeListItems();
+                assertTrue(list.size() > 0);
+
+                // There should be an activity(but with uncertain content) in position 0.
+                assertNotNull(mActivity.intentForPosition(0));
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        // Test onListItemClick
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        assertTrue(mActivity.isOnListItemClick);
+    }
+}
diff --git a/tests/app/src/android/app/cts/LauncherActivity_IconResizerTest.java b/tests/app/src/android/app/cts/LauncherActivity_IconResizerTest.java
new file mode 100644
index 0000000..b6ba9c6
--- /dev/null
+++ b/tests/app/src/android/app/cts/LauncherActivity_IconResizerTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.LauncherActivity.IconResizer;
+import android.app.stubs.LauncherActivityStub;
+import android.graphics.drawable.Drawable;
+import android.test.ActivityInstrumentationTestCase2;
+
+import android.app.stubs.R;
+
+public class LauncherActivity_IconResizerTest extends
+        ActivityInstrumentationTestCase2<LauncherActivityStub> {
+
+    private static final String PACKAGE = "android.app.stubs";
+    private LauncherActivityStub mActivity;
+
+    public LauncherActivity_IconResizerTest() {
+        super(PACKAGE, LauncherActivityStub.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+    }
+
+    public void testIconResizer() throws Throwable {
+        final IconResizer ir = mActivity.new IconResizer();
+        final Drawable d = mActivity.getResources().getDrawable(R.drawable.pass);
+        assertNotNull(d);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                Drawable thumbNail = ir.createIconThumbnail(d);
+                assertNotNull(thumbNail);
+                // The size of the thumbnail is defined by inner R resource file
+                // whose details are not open.
+                assertTrue(thumbNail.getIntrinsicHeight() > 0);
+                assertTrue(thumbNail.getIntrinsicWidth() > 0);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
+}
diff --git a/tests/app/src/android/app/cts/LauncherActivity_ListItemTest.java b/tests/app/src/android/app/cts/LauncherActivity_ListItemTest.java
new file mode 100644
index 0000000..6c22905
--- /dev/null
+++ b/tests/app/src/android/app/cts/LauncherActivity_ListItemTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.LauncherActivity;
+import android.test.AndroidTestCase;
+
+public class LauncherActivity_ListItemTest extends AndroidTestCase {
+    public void testConstructor() {
+        // Test public constructor
+        new LauncherActivity.ListItem();
+    }
+}
diff --git a/tests/app/src/android/app/cts/LaunchpadActivity.java b/tests/app/src/android/app/cts/LaunchpadActivity.java
deleted file mode 100644
index 2a90055..0000000
--- a/tests/app/src/android/app/cts/LaunchpadActivity.java
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.test.PerformanceTestCase;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-class MyBadParcelable implements Parcelable {
-    public MyBadParcelable() {
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString("I am bad");
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Parcelable.Creator<MyBadParcelable> CREATOR =
-        new Parcelable.Creator<MyBadParcelable>() {
-        public MyBadParcelable createFromParcel(Parcel in) {
-            return new MyBadParcelable(in);
-        }
-
-        public MyBadParcelable[] newArray(int size) {
-            return new MyBadParcelable[size];
-        }
-    };
-
-    public MyBadParcelable(Parcel in) {
-        in.readString();
-    }
-}
-
-public class LaunchpadActivity extends Activity {
-    public interface CallingTest extends PerformanceTestCase.Intermediates {
-        public void startTiming(boolean realTime);
-
-        public void addIntermediate(String name);
-
-        public void addIntermediate(String name, long timeInNS);
-
-        public void finishTiming(boolean realTime);
-
-        public void activityFinished(int resultCode, Intent data, RuntimeException where);
-    }
-
-    // Also used as the Binder interface descriptor string in these tests
-    public static final String LAUNCH = "android.app.cts.activity.LAUNCH";
-
-    public static final String FORWARD_RESULT = "android.app.cts.activity.FORWARD_RESULT";
-    public static final String RETURNED_RESULT = "android.app.cts.activity.RETURNED_RESULT";
-
-    public static final String BAD_PARCELABLE = "android.app.cts.activity.BAD_PARCELABLE";
-
-    public static final int LAUNCHED_RESULT = 1;
-    public static final int FORWARDED_RESULT = 2;
-
-    public static final String LIFECYCLE_BASIC = "android.app.cts.activity.LIFECYCLE_BASIC";
-    public static final String LIFECYCLE_SCREEN = "android.app.cts.activity.LIFECYCLE_SCREEN";
-    public static final String LIFECYCLE_DIALOG = "android.app.cts.activity.LIFECYCLE_DIALOG";
-
-    public static final String BROADCAST_REGISTERED = "android.app.cts.activity.BROADCAST_REGISTERED";
-    public static final String BROADCAST_LOCAL = "android.app.cts.activity.BROADCAST_LOCAL";
-    public static final String BROADCAST_REMOTE = "android.app.cts.activity.BROADCAST_REMOTE";
-    public static final String BROADCAST_ALL = "android.app.cts.activity.BROADCAST_ALL";
-    public static final String BROADCAST_REPEAT = "android.app.cts.activity.BROADCAST_REPEAT";
-    public static final String BROADCAST_MULTI = "android.app.cts.activity.BROADCAST_MULTI";
-    public static final String BROADCAST_ABORT = "android.app.cts.activity.BROADCAST_ABORT";
-
-    public static final String EXPANDLIST_SELECT = "EXPANDLIST_SELECT";
-    public static final String EXPANDLIST_VIEW = "EXPANDLIST_VIEW";
-    public static final String EXPANDLIST_CALLBACK = "EXPANDLIST_CALLBACK";
-
-    public static final String BROADCAST_STICKY1 = "android.app.cts.activity.BROADCAST_STICKY1";
-    public static final String BROADCAST_STICKY2 = "android.app.cts.activity.BROADCAST_STICKY2";
-
-    public static final String ALIAS_ACTIVITY = "android.app.cts.activity.ALIAS_ACTIVITY";
-
-    public static final String RECEIVER_REG = "receiver-reg";
-    public static final String RECEIVER_LOCAL = "receiver-local";
-    public static final String RECEIVER_REMOTE = "receiver-remote";
-    public static final String RECEIVER_ABORT = "receiver-abort";
-
-    public static final String DATA_1 = "one";
-    public static final String DATA_2 = "two";
-
-    public static final String ON_START = "onStart";
-    public static final String ON_RESTART = "onRestart";
-    public static final String ON_RESUME = "onResume";
-    public static final String ON_FREEZE = "onSaveInstanceState";
-    public static final String ON_PAUSE = "onPause";
-
-    // ON_STOP and ON_DESTROY are not tested because they may not be called.
-
-    public static final String DO_FINISH = "finish";
-    public static final String DO_LOCAL_SCREEN = "local-screen";
-    public static final String DO_LOCAL_DIALOG = "local-dialog";
-
-    private static final String TAG = "LaunchpadActivity";
-
-    private boolean mBadParcelable = false;
-
-    private boolean mStarted = false;
-
-    private int mResultCode = RESULT_CANCELED;
-    private Intent mData = new Intent().setAction("No result received");
-    private RuntimeException mResultStack = null;
-
-    /** Index into the {@link #mNextLifecycle} array. */
-    private int mNextLifecycle;
-
-    /** Current lifecycle expected to be followed. */
-    private String[] mExpectedLifecycle;
-
-    /** Other possible lifecycles. Never includes the current {@link #mExpectedLifecycle}. */
-    private List<String[]> mOtherPossibleLifecycles = new ArrayList<String[]>(2);
-
-    /** Map from lifecycle arrays to debugging log names. */
-    private Map<String[], String> mLifecycleNames = new HashMap<String[], String>(2);
-
-    private String[] mExpectedReceivers = null;
-    private int mNextReceiver;
-
-    private String[] mExpectedData = null;
-    private boolean[] mReceivedData = null;
-
-    boolean mReceiverRegistered = false;
-
-    private static CallingTest sCallingTest = null;
-
-    public static void setCallingTest(CallingTest ct) {
-        sCallingTest = ct;
-    }
-
-    public LaunchpadActivity() {
-    }
-
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        resetLifecycles();
-
-        // ON_STOP and ON_DESTROY are not tested because they may not be called.
-
-        final String action = getIntent().getAction();
-        if (LIFECYCLE_BASIC.equals(action)) {
-            addPossibleLifecycle(LIFECYCLE_BASIC, new String[] {
-                    ON_START, ON_RESUME, DO_FINISH, ON_PAUSE
-            });
-        } else if (LIFECYCLE_SCREEN.equals(action)) {
-            addPossibleLifecycle(LIFECYCLE_SCREEN + "_RESTART", new String[] {
-                    ON_START, ON_RESUME, DO_LOCAL_SCREEN, ON_PAUSE,
-                    ON_RESTART, ON_START, ON_RESUME, DO_FINISH, ON_PAUSE
-            });
-            addPossibleLifecycle(LIFECYCLE_SCREEN + "_RESUME", new String[] {
-                    ON_START, ON_RESUME, DO_LOCAL_SCREEN, ON_PAUSE,
-                    ON_RESUME, DO_FINISH, ON_PAUSE
-            });
-        } else if (LIFECYCLE_DIALOG.equals(action)) {
-            addPossibleLifecycle(LIFECYCLE_DIALOG + "_RESTART", new String[] {
-                    ON_START, ON_RESUME, DO_LOCAL_DIALOG, ON_PAUSE,
-                    ON_RESTART, ON_START, ON_RESUME, DO_FINISH, ON_PAUSE
-            });
-            addPossibleLifecycle(LIFECYCLE_DIALOG + "_RESUME", new String[] {
-                    ON_START, ON_RESUME, DO_LOCAL_DIALOG, ON_PAUSE,
-                    ON_RESUME, DO_FINISH, ON_PAUSE
-            });
-        }
-    }
-
-    private void resetLifecycles() {
-        mNextLifecycle = 0;
-        mExpectedLifecycle = null;
-        mOtherPossibleLifecycles.clear();
-        mLifecycleNames.clear();
-    }
-
-    /**
-     * Add a potential lifecycle that this activity may follow, since there
-     * are usually multiple valid lifecycles. For instance, sometimes onPause
-     * will lead to onResume rather than onStop when another activity is
-     * raised over the current one.
-     *
-     * @param debugName for the lifecycle shown in the logs
-     * @param lifecycle array containing tokens indicating the expected lifecycle
-     */
-    private void addPossibleLifecycle(String debugName, String[] lifecycle) {
-        mLifecycleNames.put(lifecycle, debugName);
-        if (mExpectedLifecycle == null) {
-            mExpectedLifecycle = lifecycle;
-        } else {
-            mOtherPossibleLifecycles.add(lifecycle);
-        }
-    }
-
-    /**
-     * Switch to the next possible lifecycle and return if switching was
-     * successful. Call this method when mExpectedLifecycle doesn't match
-     * the current lifecycle and you need to check another possible lifecycle.
-     *
-     * @return whether on not there was a lifecycle to switch to
-     */
-    private boolean switchToNextPossibleLifecycle() {
-        if (!mOtherPossibleLifecycles.isEmpty()) {
-            String[] newLifecycle = mOtherPossibleLifecycles.remove(0);
-            Log.w(TAG, "Switching expected lifecycles from "
-                    + mLifecycleNames.get(mExpectedLifecycle) + " to "
-                    + mLifecycleNames.get(newLifecycle));
-            mExpectedLifecycle = newLifecycle;
-            return true;
-        } else {
-            Log.w(TAG, "No more lifecycles after "
-                    + mLifecycleNames.get(mExpectedLifecycle));
-            mExpectedLifecycle = null;
-            return false;
-        }
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-        checkLifecycle(ON_START);
-    }
-
-    @Override
-    protected void onRestart() {
-        super.onStart();
-        checkLifecycle(ON_RESTART);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-
-        checkLifecycle(ON_RESUME);
-
-        if (!mStarted) {
-            mStarted = true;
-
-            mHandler.postDelayed(mTimeout, 10 * 1000);
-
-            final String action = getIntent().getAction();
-
-            sCallingTest.startTiming(true);
-
-            if (LAUNCH.equals(action)) {
-                final Intent intent = getIntent();
-                intent.setFlags(0);
-                intent.setComponent((ComponentName) intent.getParcelableExtra("component"));
-                startActivityForResult(intent, LAUNCHED_RESULT);
-
-            } else if (FORWARD_RESULT.equals(action)) {
-                final Intent intent = getIntent();
-                intent.setFlags(0);
-                intent.setClass(this, LocalScreen.class);
-                startActivityForResult(intent, FORWARDED_RESULT);
-            } else if (BAD_PARCELABLE.equals(action)) {
-                mBadParcelable = true;
-                final Intent intent = getIntent();
-                intent.setFlags(0);
-                intent.setClass(this, LocalScreen.class);
-                startActivityForResult(intent, LAUNCHED_RESULT);
-            } else if (BROADCAST_REGISTERED.equals(action)) {
-                setExpectedReceivers(new String[] {
-                    RECEIVER_REG
-                });
-                registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED));
-                sCallingTest.addIntermediate("after-register");
-                sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED));
-            } else if (BROADCAST_LOCAL.equals(action)) {
-                setExpectedReceivers(new String[] {
-                    RECEIVER_LOCAL
-                });
-                sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL));
-            } else if (BROADCAST_REMOTE.equals(action)) {
-                setExpectedReceivers(new String[] {
-                    RECEIVER_REMOTE
-                });
-                sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE));
-            } else if (BROADCAST_ALL.equals(action)) {
-                setExpectedReceivers(new String[] {
-                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL
-                });
-                registerMyReceiver(new IntentFilter(BROADCAST_ALL));
-                sCallingTest.addIntermediate("after-register");
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
-            } else if (BROADCAST_MULTI.equals(action)) {
-                setExpectedReceivers(new String[] {
-                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE,
-                        RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE, RECEIVER_REG,
-                        RECEIVER_LOCAL, RECEIVER_LOCAL, RECEIVER_REMOTE, RECEIVER_LOCAL,
-                        RECEIVER_REMOTE, RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
-                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE,
-                        RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE, RECEIVER_LOCAL,
-                        RECEIVER_REMOTE, RECEIVER_LOCAL
-                });
-                registerMyReceiver(new IntentFilter(BROADCAST_ALL));
-                sCallingTest.addIntermediate("after-register");
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REPEAT), null);
-            } else if (BROADCAST_ABORT.equals(action)) {
-                setExpectedReceivers(new String[] {
-                        RECEIVER_REMOTE, RECEIVER_ABORT
-                });
-                registerMyReceiver(new IntentFilter(BROADCAST_ABORT));
-                sCallingTest.addIntermediate("after-register");
-                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ABORT), null);
-            } else if (BROADCAST_STICKY1.equals(action)) {
-                setExpectedReceivers(new String[] {
-                    RECEIVER_REG
-                });
-                setExpectedData(new String[] {
-                    DATA_1
-                });
-                registerMyReceiver(new IntentFilter(BROADCAST_STICKY1));
-                sCallingTest.addIntermediate("after-register");
-            } else if (BROADCAST_STICKY2.equals(action)) {
-                setExpectedReceivers(new String[] {
-                        RECEIVER_REG, RECEIVER_REG
-                });
-                setExpectedData(new String[] {
-                        DATA_1, DATA_2
-                });
-                final IntentFilter filter = new IntentFilter(BROADCAST_STICKY1);
-                filter.addAction(BROADCAST_STICKY2);
-                registerMyReceiver(filter);
-                sCallingTest.addIntermediate("after-register");
-            } else if (ALIAS_ACTIVITY.equals(action)) {
-                final Intent intent = getIntent();
-                intent.setFlags(0);
-                intent.setClass(this, AliasActivityStub.class);
-                startActivityForResult(intent, LAUNCHED_RESULT);
-            } else if (EXPANDLIST_SELECT.equals(action)) {
-                final Intent intent = getIntent();
-                intent.setFlags(0);
-                intent.setAction(action);
-                intent.setComponent((ComponentName) intent.getParcelableExtra("component"));
-                startActivityForResult(intent, LAUNCHED_RESULT);
-            } else if (EXPANDLIST_VIEW.equals(action)) {
-                final Intent intent = getIntent();
-                intent.setFlags(0);
-                intent.setAction(action);
-                intent.setComponent((ComponentName) intent.getParcelableExtra("component"));
-                startActivityForResult(intent, LAUNCHED_RESULT);
-            } else if (EXPANDLIST_CALLBACK.equals(action)) {
-                final Intent intent = getIntent();
-                intent.setFlags(0);
-                intent.setAction(action);
-                intent.setComponent((ComponentName) intent.getParcelableExtra("component"));
-                startActivityForResult(intent, LAUNCHED_RESULT);
-            }
-        }
-    }
-
-    @Override
-    protected void onSaveInstanceState(Bundle icicle) {
-        super.onSaveInstanceState(icicle);
-        if (mBadParcelable) {
-            icicle.putParcelable("baddy", new MyBadParcelable());
-        }
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        checkLifecycle(ON_PAUSE);
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        switch (requestCode) {
-            case LAUNCHED_RESULT:
-                sCallingTest.finishTiming(true);
-                finishWithResult(resultCode, data);
-                break;
-            case FORWARDED_RESULT:
-                sCallingTest.finishTiming(true);
-                if (RETURNED_RESULT.equals(data.getAction())) {
-                    finishWithResult(resultCode, data);
-                } else {
-                    finishWithResult(RESULT_CANCELED, new Intent().setAction("Bad data returned: "
-                            + data));
-                }
-                break;
-            default:
-                sCallingTest.finishTiming(true);
-                finishWithResult(RESULT_CANCELED, new Intent()
-                        .setAction("Unexpected request code: " + requestCode));
-                break;
-        }
-    }
-
-    private void checkLifecycle(String where) {
-        String action = getIntent().getAction();
-
-        if (mExpectedLifecycle == null) {
-            return;
-        }
-
-        if (mNextLifecycle >= mExpectedLifecycle.length) {
-            finishBad("Activity lifecycle for " + action + " incorrect: received " + where
-                    + " but don't expect any more calls");
-            mExpectedLifecycle = null;
-            return;
-        }
-
-        do {
-            if (mExpectedLifecycle[mNextLifecycle].equals(where)) {
-                Log.w(TAG, "Matched: " + where);
-                break;
-            } else {
-                Log.w(TAG, "Expected " + mExpectedLifecycle[mNextLifecycle] + " but got " + where);
-            }
-        } while (switchToNextPossibleLifecycle());
-
-        if (mExpectedLifecycle == null) {
-            finishBad("Activity lifecycle for " + action + " incorrect: received " + where
-                    + " at " + mNextLifecycle);
-            return;
-        }
-
-        mNextLifecycle++;
-
-        if (mNextLifecycle >= mExpectedLifecycle.length) {
-            finishGood();
-            return;
-        }
-
-        final String next = mExpectedLifecycle[mNextLifecycle];
-        if (next.equals(DO_FINISH)) {
-            mNextLifecycle++;
-            if (mNextLifecycle >= mExpectedLifecycle.length) {
-                setTestResult(RESULT_OK, null);
-            }
-            if (!isFinishing()) {
-                finish();
-            }
-        } else if (next.equals(DO_LOCAL_SCREEN)) {
-            mNextLifecycle++;
-            final Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
-            intent.setClass(this, LocalScreen.class);
-            startActivity(intent);
-        } else if (next.equals(DO_LOCAL_DIALOG)) {
-            mNextLifecycle++;
-            final Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
-            intent.setClass(this, LocalDialog.class);
-            startActivity(intent);
-        }
-    }
-
-    private void setExpectedReceivers(String[] receivers) {
-        mExpectedReceivers = receivers;
-        mNextReceiver = 0;
-    }
-
-    private void setExpectedData(String[] data) {
-        mExpectedData = data;
-        mReceivedData = new boolean[data.length];
-    }
-
-    @SuppressWarnings("deprecation")
-    private Intent makeBroadcastIntent(String action) {
-        final Intent intent = new Intent(action, null);
-        intent.putExtra("caller", mCallTarget);
-        return intent;
-    }
-
-    private void finishGood() {
-        finishWithResult(RESULT_OK, null);
-    }
-
-    private void finishBad(String error) {
-        finishWithResult(RESULT_CANCELED, new Intent().setAction(error));
-    }
-
-    private void finishWithResult(int resultCode, Intent data) {
-        setTestResult(resultCode, data);
-        finish();
-
-        // Member fields set by calling setTestResult above...
-        sCallingTest.activityFinished(mResultCode, mData, mResultStack);
-    }
-
-    private void setTestResult(int resultCode, Intent data) {
-        mHandler.removeCallbacks(mTimeout);
-        unregisterMyReceiver();
-        mResultCode = resultCode;
-        mData = data;
-        mResultStack = new RuntimeException("Original error was here");
-        mResultStack.fillInStackTrace();
-    }
-
-    private void registerMyReceiver(IntentFilter filter) {
-        mReceiverRegistered = true;
-        registerReceiver(mReceiver, filter);
-    }
-
-    private void unregisterMyReceiver() {
-        if (mReceiverRegistered) {
-            mReceiverRegistered = false;
-            unregisterReceiver(mReceiver);
-        }
-    }
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-        }
-    };
-
-    static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
-    static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1;
-
-    private final Binder mCallTarget = new Binder() {
-        @Override
-        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
-            data.setDataPosition(0);
-            data.enforceInterface(LaunchpadActivity.LAUNCH);
-            if (code == GOT_RECEIVE_TRANSACTION) {
-                final String name = data.readString();
-                gotReceive(name, null);
-                return true;
-            } else if (code == ERROR_TRANSACTION) {
-                finishBad(data.readString());
-                return true;
-            }
-            return false;
-        }
-    };
-
-    private final void gotReceive(String name, Intent intent) {
-        synchronized (this) {
-
-            sCallingTest.addIntermediate(mNextReceiver + "-" + name);
-
-            if (mExpectedData != null) {
-                final int n = mExpectedData.length;
-                int i;
-                boolean prev = false;
-                for (i = 0; i < n; i++) {
-                    if (mExpectedData[i].equals(intent.getStringExtra("test"))) {
-                        if (mReceivedData[i]) {
-                            prev = true;
-                            continue;
-                        }
-                        mReceivedData[i] = true;
-                        break;
-                    }
-                }
-                if (i >= n) {
-                    if (prev) {
-                        finishBad("Receive got data too many times: "
-                                + intent.getStringExtra("test"));
-                    } else {
-                        finishBad("Receive got unexpected data: " + intent.getStringExtra("test"));
-                    }
-                    return;
-                }
-            }
-
-            if (mNextReceiver >= mExpectedReceivers.length) {
-                finishBad("Got too many onReceiveIntent() calls!");
-            } else if (!mExpectedReceivers[mNextReceiver].equals(name)) {
-                finishBad("Receive out of order: got " + name + " but expected "
-                        + mExpectedReceivers[mNextReceiver] + " at " + mNextReceiver);
-            } else {
-                mNextReceiver++;
-                if (mNextReceiver == mExpectedReceivers.length) {
-                    mHandler.post(mUnregister);
-                }
-            }
-
-        }
-    }
-
-    private final Runnable mUnregister = new Runnable() {
-        public void run() {
-            if (mReceiverRegistered) {
-                sCallingTest.addIntermediate("before-unregister");
-                unregisterMyReceiver();
-            }
-            sCallingTest.finishTiming(true);
-            finishGood();
-        }
-    };
-
-    private final Runnable mTimeout = new Runnable() {
-        public void run() {
-            Log.i(TAG, "timeout");
-            String msg = "Timeout";
-            if (mExpectedReceivers != null && mNextReceiver < mExpectedReceivers.length) {
-                msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver];
-            }
-            finishBad(msg);
-        }
-    };
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            gotReceive(RECEIVER_REG, intent);
-        }
-    };
-}
diff --git a/tests/app/src/android/app/cts/LaunchpadTabActivity.java b/tests/app/src/android/app/cts/LaunchpadTabActivity.java
deleted file mode 100644
index 3dfd2c3..0000000
--- a/tests/app/src/android/app/cts/LaunchpadTabActivity.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.TabActivity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.TabHost;
-
-public class LaunchpadTabActivity extends TabActivity {
-    public LaunchpadTabActivity() {
-    }
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        final Intent tabIntent = new Intent(getIntent());
-        tabIntent.setComponent((ComponentName) tabIntent.getParcelableExtra("tab"));
-
-        final TabHost th = getTabHost();
-        final TabHost.TabSpec ts = th.newTabSpec("1");
-        ts.setIndicator("One");
-        ts.setContent(tabIntent);
-        th.addTab(ts);
-    }
-}
diff --git a/tests/app/src/android/app/cts/LifecycleTest.java b/tests/app/src/android/app/cts/LifecycleTest.java
new file mode 100644
index 0000000..8b08dcb
--- /dev/null
+++ b/tests/app/src/android/app/cts/LifecycleTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.stubs.ActivityTestsBase;
+import android.app.stubs.LaunchpadActivity;
+import android.app.stubs.LaunchpadTabActivity;
+import android.content.ComponentName;
+import android.content.Intent;
+
+public class LifecycleTest extends ActivityTestsBase {
+    private Intent mTopIntent;
+    private Intent mTabIntent;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTopIntent = mIntent;
+        mTabIntent = new Intent(mContext, LaunchpadTabActivity.class);
+        mTabIntent.putExtra("tab", new ComponentName(mContext, LaunchpadActivity.class));
+    }
+
+    public void testTabDialog() {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG);
+    }
+
+    public void testDialog() {
+        mIntent = mTopIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG);
+    }
+
+    public void testTabScreen() {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN);
+    }
+
+    public void testScreen() {
+        mIntent = mTopIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN);
+    }
+
+    public void testTabBasic() {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC);
+    }
+
+    public void testBasic() {
+        mIntent = mTopIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC);
+    }
+}
diff --git a/tests/app/src/android/app/cts/LocalActivity.java b/tests/app/src/android/app/cts/LocalActivity.java
deleted file mode 100644
index 67fad8c..0000000
--- a/tests/app/src/android/app/cts/LocalActivity.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-public class LocalActivity extends TestedActivity {
-    public LocalActivity() {
-    }
-}
diff --git a/tests/app/src/android/app/cts/LocalActivityManagerStubActivity.java b/tests/app/src/android/app/cts/LocalActivityManagerStubActivity.java
deleted file mode 100644
index e64c75a..0000000
--- a/tests/app/src/android/app/cts/LocalActivityManagerStubActivity.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class LocalActivityManagerStubActivity extends Activity{
-
-    public static boolean sIsOnResumeCalled;
-    public static boolean sIsOnStopCalled;
-    public static boolean sIsOnPauseCalled;
-    public static boolean sIsOnDestroyCalled;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        sIsOnResumeCalled = true;
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        sIsOnStopCalled = true;
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        sIsOnPauseCalled = true;
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        sIsOnDestroyCalled = true;
-    }
-}
diff --git a/tests/app/src/android/app/cts/LocalActivityManagerTest.java b/tests/app/src/android/app/cts/LocalActivityManagerTest.java
new file mode 100644
index 0000000..7f6fd2f
--- /dev/null
+++ b/tests/app/src/android/app/cts/LocalActivityManagerTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.LocalActivityManager;
+import android.app.stubs.LocalActivityManagerTestHelper;
+import android.content.Intent;
+import android.cts.util.CTSResult;
+import android.test.InstrumentationTestCase;
+import android.test.UiThreadTest;
+
+public class LocalActivityManagerTest extends InstrumentationTestCase implements CTSResult {
+
+    private Instrumentation mInstrumentation;
+
+    private Sync mSync = new Sync();
+    private static class Sync {
+        public boolean mHasNotify;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mSync = new Sync();
+    }
+
+    private void setupActivity(final String action) {
+        final Intent intent = new Intent(mInstrumentation.getTargetContext(),
+                LocalActivityManagerTestHelper.class);
+        intent.setAction(action);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mInstrumentation.getTargetContext().startActivity(intent);
+    }
+
+    @UiThreadTest
+    public void testConstructor() {
+        new LocalActivityManager(new Activity(), true);
+        new LocalActivityManager(new Activity(), false);
+        new LocalActivityManager(null, false);
+        new LocalActivityManager(null, true);
+    }
+
+    public void testDispatchResume() throws InterruptedException {
+        LocalActivityManagerTestHelper.setResult(this);
+        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_RESUME);
+        waitForResult();
+    }
+
+    private void waitForResult() throws InterruptedException {
+        synchronized (mSync) {
+            if (!mSync.mHasNotify) {
+                mSync.wait();
+            }
+        }
+    }
+
+    public void testStartActivity() throws InterruptedException {
+        LocalActivityManagerTestHelper.setResult(this);
+        setupActivity(LocalActivityManagerTestHelper.ACTION_START_ACTIVITY);
+        waitForResult();
+    }
+
+    public void testDispatchCreate() throws InterruptedException {
+        LocalActivityManagerTestHelper.setResult(this);
+        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_CREATE);
+        waitForResult();
+    }
+
+    public void testDispatchStop() throws InterruptedException {
+        LocalActivityManagerTestHelper.setResult(this);
+        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_STOP);
+        waitForResult();
+    }
+
+    public void testDispatchPauseTrue() throws InterruptedException {
+        LocalActivityManagerTestHelper.setResult(this);
+        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_PAUSE_TRUE);
+        waitForResult();
+    }
+
+    public void testDispatchPauseFalse() throws InterruptedException {
+        LocalActivityManagerTestHelper.setResult(this);
+        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_PAUSE_FALSE);
+        waitForResult();
+    }
+
+    public void testSaveInstanceState() throws InterruptedException {
+        LocalActivityManagerTestHelper.setResult(this);
+        setupActivity(LocalActivityManagerTestHelper.ACTION_SAVE_INSTANCE_STATE);
+        waitForResult();
+    }
+
+    public void testDispatchDestroy() throws InterruptedException {
+        LocalActivityManagerTestHelper.setResult(this);
+        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_DESTROY);
+        waitForResult();
+    }
+
+    public void testRemoveAllActivities() throws InterruptedException {
+        LocalActivityManagerTestHelper.setResult(this);
+        setupActivity(LocalActivityManagerTestHelper.ACTION_REMOVE_ALL_ACTIVITY);
+        waitForResult();
+    }
+
+    public void setResult(final int resultCode) {
+        synchronized (mSync) {
+            mSync.mHasNotify = true;
+            mSync.notify();
+            assertEquals(CTSResult.RESULT_OK, resultCode);
+        }
+    }
+
+    public void setResult(Exception e) {
+        setResult(CTSResult.RESULT_FAIL);
+    }
+
+}
diff --git a/tests/app/src/android/app/cts/LocalActivityManagerTestHelper.java b/tests/app/src/android/app/cts/LocalActivityManagerTestHelper.java
deleted file mode 100644
index 70764e4..0000000
--- a/tests/app/src/android/app/cts/LocalActivityManagerTestHelper.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.app.cts;
-
-
-import android.app.Activity;
-import android.app.ActivityGroup;
-import android.app.LocalActivityManager;
-import android.content.Intent;
-import android.cts.util.CTSResult;
-import android.os.Bundle;
-import android.view.Window;
-
-public class LocalActivityManagerTestHelper extends ActivityGroup {
-
-    public static final String ACTION_DISPATCH_RESUME = "dispatchResume";
-    public static final String ACTION_START_ACTIVITY = "startActivity";
-    public static final String ACTION_DISPATCH_CREATE = "dispatchCreate";
-    public static final String ACTION_DISPATCH_STOP = "dispatchStop";
-    public static final String ACTION_DISPATCH_PAUSE_TRUE = "dispatchPauseTrue";
-    public static final String ACTION_DISPATCH_PAUSE_FALSE = "dispatchPauseFalse";
-    public static final String ACTION_SAVE_INSTANCE_STATE = "saveInstanceState";
-    public static final String ACTION_DISPATCH_DESTROY = "dispatchDestroy";
-    public static final String ACTION_REMOVE_ALL_ACTIVITY = "removeAllActivities";
-
-    private String mCurrentAction;
-    private LocalActivityManager mLocalActivityManager;
-
-    private static CTSResult sResult;
-
-    public static void setResult(CTSResult cr) {
-        sResult = cr;
-    }
-
-    public LocalActivityManagerTestHelper() {
-        super();
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mCurrentAction = getIntent().getAction();
-        mLocalActivityManager = getLocalActivityManager();
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-    }
-
-    protected void onResume() {
-        super.onResume();
-        if (mCurrentAction.equals(ACTION_DISPATCH_RESUME)) {
-            testDispatchResume();
-        } else if (mCurrentAction.equals(ACTION_START_ACTIVITY)) {
-            testStartActivity();
-        } else if (mCurrentAction.equals(ACTION_DISPATCH_CREATE)) {
-            testDispatchCreate();
-        } else if (mCurrentAction.equals(ACTION_DISPATCH_STOP)) {
-            testDispatchStop();
-        } else if (mCurrentAction.equals(ACTION_DISPATCH_PAUSE_TRUE)) {
-            testDispatchPauseTrue();
-        } else if (mCurrentAction.equals(ACTION_DISPATCH_PAUSE_FALSE)) {
-            testDispatchPauseFalse();
-        } else if (mCurrentAction.equals(ACTION_SAVE_INSTANCE_STATE)) {
-            testSaveInstanceState();
-        } else if (mCurrentAction.equals(ACTION_DISPATCH_DESTROY)) {
-            testDispatchDestroy();
-        } else if (mCurrentAction.equals(ACTION_REMOVE_ALL_ACTIVITY)) {
-            testRemoveAllActivity();
-        }
-    }
-
-    private void testRemoveAllActivity() {
-        final String id = "id_remove_activity";
-        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mLocalActivityManager.startActivity(id, intent);
-
-        Activity activity = mLocalActivityManager.getActivity(id);
-        if (activity == null) {
-            fail();
-            return;
-        }
-
-        if (!activity.getClass().getName().equals("android.app.cts."
-                    + "LocalActivityManagerStubActivity")) {
-            fail();
-            return;
-        }
-
-        mLocalActivityManager.removeAllActivities();
-        activity = mLocalActivityManager.getActivity(id);
-        if (activity != null) {
-            fail();
-            return;
-        }
-        pass();
-    }
-
-    private void testDispatchDestroy() {
-        final String id1 = "id_dispatch_destroy1";
-        final String id2 = "id_dispatch_destroy2";
-        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mLocalActivityManager.startActivity(id1, intent);
-
-        LocalActivityManagerStubActivity.sIsOnDestroyCalled = false;
-        mLocalActivityManager.dispatchDestroy(false);
-        if (mLocalActivityManager.getCurrentActivity().isFinishing()){
-            fail();
-            return;
-        }
-
-        if (!LocalActivityManagerStubActivity.sIsOnDestroyCalled) {
-            fail();
-            return;
-        }
-
-        mLocalActivityManager.startActivity(id2, intent);
-        LocalActivityManagerStubActivity.sIsOnDestroyCalled = false;
-        mLocalActivityManager.dispatchDestroy(true);
-
-        if (!LocalActivityManagerStubActivity.sIsOnDestroyCalled) {
-            fail();
-            return;
-        }
-
-        if (!mLocalActivityManager.getCurrentActivity().isFinishing()){
-            fail();
-            return;
-        }
-        pass();
-    }
-
-    private void testSaveInstanceState() {
-        final String key = "_id1";
-        mLocalActivityManager.dispatchCreate(null);
-        final Bundle bundle = mLocalActivityManager.saveInstanceState();
-        if (bundle != null) {
-            fail();
-            return;
-        }
-
-        final String id = "id_dispatch_pause";
-        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mLocalActivityManager.startActivity(id, intent);
-
-        final Bundle savedBundle = new Bundle();
-        final Bundle bb = new Bundle();
-        savedBundle.putBundle(key, bb);
-
-        mLocalActivityManager.dispatchCreate(savedBundle);
-        final Bundle returnedBundle = mLocalActivityManager.saveInstanceState();
-        if (returnedBundle.getBundle(key) == null ) {
-            fail();
-            return;
-        }
-        pass();
-    }
-
-    private void testDispatchPauseFalse() {
-        final String id = "id_dispatch_pause";
-        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mLocalActivityManager.startActivity(id, intent);
-        LocalActivityManagerStubActivity.sIsOnPauseCalled = false;
-        mLocalActivityManager.dispatchPause(false);
-        if (!LocalActivityManagerStubActivity.sIsOnPauseCalled) {
-            fail();
-            return;
-        }
-        pass();
-    }
-
-    private void testDispatchPauseTrue() {
-        final String id = "id_dispatch_pause";
-        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mLocalActivityManager.startActivity(id, intent);
-        LocalActivityManagerStubActivity.sIsOnPauseCalled = false;
-        mLocalActivityManager.dispatchPause(true);
-        if (!LocalActivityManagerStubActivity.sIsOnPauseCalled) {
-            fail();
-            return;
-        }
-        pass();
-    }
-
-    private void testDispatchStop() {
-        final String id = "id_dispatch_stop";
-        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mLocalActivityManager.startActivity(id, intent);
-        if (mLocalActivityManager.getCurrentActivity() == null) {
-            fail();
-            return;
-        }
-
-        LocalActivityManagerStubActivity.sIsOnStopCalled = false;
-        mLocalActivityManager.dispatchStop();
-
-        if (!LocalActivityManagerStubActivity.sIsOnStopCalled) {
-            fail();
-            return;
-        }
-        pass();
-    }
-
-    private void testDispatchCreate() {
-        final Bundle EXPECTED = new Bundle();
-        final String id = "id";
-
-        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mLocalActivityManager.startActivity("_id" + System.currentTimeMillis(), intent);
-        final Bundle bundle = mLocalActivityManager.saveInstanceState();
-        if (bundle == null) {
-            fail();
-            return;
-        }
-
-        if (bundle.keySet().size() != 1) {
-            fail();
-            return;
-        }
-
-        bundle.putBundle(id, EXPECTED);
-        // test null parameter
-        mLocalActivityManager.dispatchCreate(null);
-
-        if (mLocalActivityManager.saveInstanceState().keySet().size() != 1) {
-            fail();
-            return;
-        }
-
-        mLocalActivityManager.dispatchCreate(bundle);
-
-        final Bundle b = mLocalActivityManager.saveInstanceState();
-        final Bundle bb = b.getBundle(id);
-        if (bb != EXPECTED) {
-            fail();
-            return;
-        }
-        pass();
-    }
-
-    private void testStartActivity() {
-        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        final String id = "_id_resume_test";
-        final Window w = mLocalActivityManager.startActivity(id, intent);
-        if (w == null) {
-            fail();
-            return;
-        }
-
-        Activity activity = mLocalActivityManager.getActivity(id);
-        if (activity == null) {
-            fail();
-            return;
-        }
-
-        // testing null id
-        activity = mLocalActivityManager.getActivity("null id");
-        if (activity != null) {
-            fail();
-            return;
-        }
-
-        if (!mLocalActivityManager.getCurrentId().equals(id)) {
-            fail();
-            return;
-        }
-
-        if (mLocalActivityManager.getActivity(id) != mLocalActivityManager
-                .getCurrentActivity()) {
-            fail();
-            return;
-        }
-
-        if (mLocalActivityManager.destroyActivity(id, true) == null) {
-            fail();
-            return;
-        }
-
-        if (mLocalActivityManager.startActivity(null, intent) == null) {
-            fail();
-            return;
-        }
-
-        try {
-            // test when calling startActivity with both null parameter.
-            mLocalActivityManager.startActivity(null, null);
-            fail();
-            return;
-        } catch (NullPointerException e) {
-        }
-        pass();
-    }
-
-    private void testDispatchResume() {
-        final Intent intent = new Intent(this, LocalActivityManagerStubActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mLocalActivityManager.startActivity("_id_resume_test", intent);
-        mLocalActivityManager.dispatchStop();
-        LocalActivityManagerStubActivity.sIsOnResumeCalled = false;
-        mLocalActivityManager.dispatchResume();
-        if (LocalActivityManagerStubActivity.sIsOnResumeCalled) {
-            pass();
-        } else {
-            fail();
-        }
-    }
-
-    private void fail() {
-        sResult.setResult(CTSResult.RESULT_FAIL);
-        finish();
-    }
-
-    private void pass() {
-        sResult.setResult(CTSResult.RESULT_OK);
-        finish();
-    }
-}
diff --git a/tests/app/src/android/app/cts/LocalDeniedService.java b/tests/app/src/android/app/cts/LocalDeniedService.java
deleted file mode 100644
index d3c9153..0000000
--- a/tests/app/src/android/app/cts/LocalDeniedService.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-public class LocalDeniedService extends LocalService
-{
-}
-
diff --git a/tests/app/src/android/app/cts/LocalDialog.java b/tests/app/src/android/app/cts/LocalDialog.java
deleted file mode 100644
index ec670fc..0000000
--- a/tests/app/src/android/app/cts/LocalDialog.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-public class LocalDialog extends TestedScreen {
-    public LocalDialog() {
-    }
-}
diff --git a/tests/app/src/android/app/cts/LocalGrantedService.java b/tests/app/src/android/app/cts/LocalGrantedService.java
deleted file mode 100644
index c073f12..0000000
--- a/tests/app/src/android/app/cts/LocalGrantedService.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-public class LocalGrantedService extends LocalService
-{
-}
-
diff --git a/tests/app/src/android/app/cts/LocalScreen.java b/tests/app/src/android/app/cts/LocalScreen.java
deleted file mode 100644
index 87f5530..0000000
--- a/tests/app/src/android/app/cts/LocalScreen.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-public class LocalScreen extends TestedScreen {
-    public LocalScreen() {
-    }
-}
diff --git a/tests/app/src/android/app/cts/LocalService.java b/tests/app/src/android/app/cts/LocalService.java
deleted file mode 100644
index 6c4ae99..0000000
--- a/tests/app/src/android/app/cts/LocalService.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Service;
-import android.content.Intent;
-import android.cts.util.IBinderParcelable;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
-
-public class LocalService extends Service {
-    public static final String SERVICE_LOCAL =
-            "android.app.cts.activity.SERVICE_LOCAL";
-    public static final String SERVICE_LOCAL_GRANTED =
-            "android.app.cts.activity.SERVICE_LOCAL_GRANTED";
-    public static final String SERVICE_LOCAL_DENIED =
-            "android.app.cts.activity.SERVICE_LOCAL_DENIED";
-
-    public static final String REPORT_OBJ_NAME = "report";
-
-    public static final int STARTED_CODE = 1;
-    public static final int DESTROYED_CODE = 2;
-    public static final int SET_REPORTER_CODE = 3;
-    public static final int UNBIND_CODE = 4;
-    public static final int REBIND_CODE = 5;
-
-    private IBinder mReportObject;
-    private int mStartCount = 1;
-
-    private final IBinder mBinder = new Binder() {
-        @Override
-        protected boolean onTransact(int code, Parcel data, Parcel reply,
-                int flags) throws RemoteException {
-            if (code == SET_REPORTER_CODE) {
-                data.enforceInterface(SERVICE_LOCAL);
-                mReportObject = data.readStrongBinder();
-                return true;
-            } else {
-                return super.onTransact(code, data, reply, flags);
-            }
-        }
-    };
-
-
-    public LocalService() {
-    }
-
-    @Override
-    public void onStart(Intent intent, int startId) {
-        if (intent.getExtras() != null) {
-            IBinderParcelable parcelable
-                    = (IBinderParcelable) intent.getExtras().getParcelable(REPORT_OBJ_NAME);
-            mReportObject = parcelable.binder;
-            if (mReportObject != null) {
-                bindAction(STARTED_CODE);
-            }
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        if (mReportObject != null) {
-            bindAction(DESTROYED_CODE);
-        }
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mBinder;
-    }
-
-    @Override
-    public boolean onUnbind(Intent intent) {
-        if (mReportObject != null) {
-            bindAction(UNBIND_CODE);
-        }
-        return true;
-    }
-
-    @Override
-    public void onRebind(Intent intent) {
-        if (mReportObject != null) {
-            bindAction(REBIND_CODE);
-        }
-    }
-
-    private void bindAction(final int bindCode) {
-        try {
-            Parcel data = Parcel.obtain();
-            data.writeInterfaceToken(SERVICE_LOCAL);
-            if (bindCode == STARTED_CODE) {
-                data.writeInt(mStartCount);
-                mStartCount++;
-            }
-            mReportObject.transact(
-                    bindCode, data, null, 0);
-            data.recycle();
-        } catch (RemoteException e) {
-            // fail
-        }
-    }
-}
diff --git a/tests/app/src/android/app/cts/MockActivity.java b/tests/app/src/android/app/cts/MockActivity.java
deleted file mode 100644
index 8d10c71..0000000
--- a/tests/app/src/android/app/cts/MockActivity.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-
-public class MockActivity extends Activity {
-
-}
diff --git a/tests/app/src/android/app/cts/MockAlarmReceiver.java b/tests/app/src/android/app/cts/MockAlarmReceiver.java
deleted file mode 100644
index 8745db6..0000000
--- a/tests/app/src/android/app/cts/MockAlarmReceiver.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.SystemClock;
-
-/**
- * this class  receive alarm from AlarmManagerTest
- */
-public class MockAlarmReceiver extends BroadcastReceiver {
-    private final Object mSync = new Object();
-    public final String mTargetAction;
-
-    public volatile boolean alarmed = false;
-    public volatile long elapsedTime;
-    public volatile long rtcTime;
-
-    public MockAlarmReceiver(String targetAction) {
-        mTargetAction = targetAction;
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        final String action = intent.getAction();
-        if (action.equals(mTargetAction)) {
-            synchronized (mSync) {
-                alarmed = true;
-                elapsedTime = SystemClock.elapsedRealtime();
-                rtcTime = System.currentTimeMillis();
-            }
-        }
-    }
-
-    public void setAlarmedFalse() {
-        synchronized (mSync) {
-            alarmed = false;
-        }
-    }
-}
diff --git a/tests/app/src/android/app/cts/MockApplication.java b/tests/app/src/android/app/cts/MockApplication.java
deleted file mode 100644
index 0d0cb43..0000000
--- a/tests/app/src/android/app/cts/MockApplication.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Application;
-import android.content.res.Configuration;
-
-
-public class MockApplication extends Application {
-
-    public boolean isOnCreateCalled;
-    public boolean isConstructorCalled;
-    public boolean isOnConfigurationChangedCalled;
-    public boolean isOnLowMemoryCalled;
-
-    public MockApplication() {
-        super();
-        isConstructorCalled = true;
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        isOnCreateCalled = true;
-    }
-
-    @Override
-    public void onTerminate() {
-        super.onTerminate();
-        // The documentation states that one cannot rely on this method being called. No need to
-        // test it here.
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        isOnConfigurationChangedCalled = true;
-    }
-
-    @Override
-    public void onLowMemory() {
-        super.onLowMemory();
-        isOnLowMemoryCalled = true;
-    }
-}
diff --git a/tests/app/src/android/app/cts/MockApplicationActivity.java b/tests/app/src/android/app/cts/MockApplicationActivity.java
deleted file mode 100644
index 40299ee..0000000
--- a/tests/app/src/android/app/cts/MockApplicationActivity.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.TextView;
-
-public class MockApplicationActivity extends Activity {
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        TextView textView = new TextView(this);
-        textView.setText("Test");
-        setContentView(textView);
-    }
-
-}
diff --git a/tests/app/src/android/app/cts/MockReceiver.java b/tests/app/src/android/app/cts/MockReceiver.java
deleted file mode 100644
index d102cbe..0000000
--- a/tests/app/src/android/app/cts/MockReceiver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class MockReceiver extends BroadcastReceiver {
-
-    // PendingIntent may return same instance or new instance, so static variable is needed.
-    public static int sResultCode = 0;
-    public static final String MOCKACTION = "android.app.PendingIntentTest.TEST_RECEIVER";
-    public static String sAction;
-
-    /**
-     * set the result as true when received alarm
-     */
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        sAction = intent.getAction();
-        if (sAction.equals(MOCKACTION)) {
-            sResultCode = getResultCode();
-        }
-    }
-}
-
diff --git a/tests/app/src/android/app/cts/MockService.java b/tests/app/src/android/app/cts/MockService.java
deleted file mode 100644
index 510e731..0000000
--- a/tests/app/src/android/app/cts/MockService.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Binder;
-import android.os.IBinder;
-
-public class MockService extends Service {
-    public static boolean result = false;
-    private final IBinder mBinder = new MockBinder();
-
-    public class MockBinder extends Binder {
-        MockService getService() {
-            return MockService.this;
-        }
-    }
-
-    /**
-     * set the result as true when service bind
-     */
-    @Override
-    public IBinder onBind(Intent intent) {
-        result = true;
-        return mBinder;
-    }
-
-    /**
-     * set the result as true when service start
-     */
-    @Override
-    public void onStart(Intent intent, int startId) {
-        super.onStart(intent, startId);
-        result = true;
-    }
-}
-
diff --git a/tests/app/src/android/app/cts/MockTabActivity.java b/tests/app/src/android/app/cts/MockTabActivity.java
deleted file mode 100644
index aca19f5..0000000
--- a/tests/app/src/android/app/cts/MockTabActivity.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.app.TabActivity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.TabHost;
-
-public class MockTabActivity extends TabActivity {
-
-    private static final String TAB1 = "tab1";
-    private static final String TAB2 = "tab2";
-    private static final String TAB3 = "tab3";
-
-    public boolean isOnChildTitleChangedCalled;
-    public boolean isOnPostCreateCalled;
-    public boolean isOnSaveInstanceStateCalled;
-    public boolean isOnContentChangedCalled;
-    public static boolean isOnRestoreInstanceStateCalled;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        final TabHost tabHost = getTabHost();
-
-        tabHost.addTab(tabHost.newTabSpec(TAB1).setIndicator(TAB1)
-                .setContent(new Intent(this, ChildTabActivity.class)));
-
-        tabHost.addTab(tabHost.newTabSpec(TAB2).setIndicator(TAB2)
-                .setContent(new Intent(this, MockActivity.class)));
-
-        tabHost.addTab(tabHost.newTabSpec(TAB3).setIndicator(TAB3).setContent(
-                new Intent(this, AppStubActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)));
-
-    }
-
-    @Override
-    protected void onChildTitleChanged(Activity childActivity, CharSequence title) {
-        super.onChildTitleChanged(childActivity, title);
-        isOnChildTitleChangedCalled = true;
-    }
-
-    @Override
-    protected void onPostCreate(Bundle icicle) {
-        super.onPostCreate(icicle);
-        isOnPostCreateCalled = true;
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Bundle state) {
-        super.onRestoreInstanceState(state);
-        isOnRestoreInstanceStateCalled = true;
-    }
-
-    @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        isOnSaveInstanceStateCalled = true;
-    }
-
-    @Override
-    public void onContentChanged() {
-        super.onContentChanged();
-        isOnContentChangedCalled = true;
-    }
-}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
new file mode 100644
index 0000000..04aeecd
--- /dev/null
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Telephony.Threads;
+import android.service.notification.StatusBarNotification;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import android.app.stubs.R;
+
+public class NotificationManagerTest extends AndroidTestCase {
+    final String TAG = NotificationManagerTest.class.getSimpleName();
+    final boolean DEBUG = false;
+
+    private NotificationManager mNotificationManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mNotificationManager = (NotificationManager) mContext.getSystemService(
+                Context.NOTIFICATION_SERVICE);
+        // clear the deck so that our getActiveNotifications results are predictable
+        mNotificationManager.cancelAll();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mNotificationManager.cancelAll();
+    }
+
+    public void testNotify() {
+        mNotificationManager.cancelAll();
+
+        final int id = 1;
+        sendNotification(id, R.drawable.black);
+        // test updating the same notification
+        sendNotification(id, R.drawable.blue);
+        sendNotification(id, R.drawable.yellow);
+
+        // assume that sendNotification tested to make sure individual notifications were present
+        StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
+        for (StatusBarNotification sbn : sbns) {
+            if (sbn.getId() != id) {
+                fail("we got back other notifications besides the one we posted: "
+                        + sbn.getKey());
+            }
+        }
+    }
+
+    public void testCancel() {
+        final int id = 9;
+        sendNotification(id, R.drawable.black);
+        mNotificationManager.cancel(id);
+
+        if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
+            fail("canceled notification was still alive, id=" + id);
+        }
+    }
+
+    public void testCancelAll() {
+        sendNotification(1, R.drawable.black);
+        sendNotification(2, R.drawable.blue);
+        sendNotification(3, R.drawable.yellow);
+
+        if (DEBUG) {
+            Log.d(TAG, "posted 3 notifications, here they are: ");
+            StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
+            for (StatusBarNotification sbn : sbns) {
+                Log.d(TAG, "  " + sbn);
+            }
+            Log.d(TAG, "about to cancel...");
+        }
+        mNotificationManager.cancelAll();
+
+        StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
+        assertTrue("notification list was not empty after cancelAll", sbns.length == 0);
+    }
+
+    private void sendNotification(final int id, final int icon) {
+        final Intent intent = new Intent(Intent.ACTION_MAIN, Threads.CONTENT_URI);
+
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        intent.setAction(Intent.ACTION_MAIN);
+
+        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+        final Notification notification = new Notification.Builder(mContext)
+                .setSmallIcon(icon)
+                .setWhen(System.currentTimeMillis())
+                .setContentTitle("notify#" + id)
+                .setContentText("This is #" + id + "notification  ")
+                .setContentIntent(pendingIntent)
+                .build();
+        mNotificationManager.notify(id, notification);
+
+
+        if (!checkNotificationExistence(id, /*shouldExist=*/ true)) {
+            fail("couldn't find posted notification id=" + id);
+        }
+    }
+
+    private boolean checkNotificationExistence(int id, boolean shouldExist) {
+        // notification is a bit asynchronous so it may take a few ms to appear in getActiveNotifications()
+        // we will check for it for up to 200ms before giving up
+        boolean found = false;
+        for (int tries=3; tries-->0;) {
+            final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
+            for (StatusBarNotification sbn : sbns) {
+                if (sbn.getId() == id) {
+                    found = true;
+                    break;
+                }
+            }
+            if (found == shouldExist) break;
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {
+                // pass
+            }
+        }
+        return found == shouldExist;
+    }
+}
diff --git a/tests/app/src/android/app/cts/NotificationTest.java b/tests/app/src/android/app/cts/NotificationTest.java
new file mode 100644
index 0000000..9da1b25
--- /dev/null
+++ b/tests/app/src/android/app/cts/NotificationTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Notification;
+import android.app.Notification.Topic;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.widget.RemoteViews;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class NotificationTest extends AndroidTestCase {
+
+    private Notification mNotification;
+    private Context mContext;
+
+    private static final String TICKER_TEXT = "tickerText";
+    private static final String CONTENT_TITLE = "contentTitle";
+    private static final String CONTENT_TEXT = "contentText";
+    private static final String URI_STRING = "uriString";
+    private static final int TOLERANCE = 200;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getContext();
+        mNotification = new Notification();
+    }
+
+    public void testConstructor() {
+        mNotification = null;
+        mNotification = new Notification();
+        assertNotNull(mNotification);
+        assertTrue(System.currentTimeMillis() - mNotification.when < TOLERANCE);
+
+        mNotification = null;
+        final int notificationTime = 200;
+        mNotification = new Notification(0, TICKER_TEXT, notificationTime);
+        assertEquals(notificationTime, mNotification.when);
+        assertEquals(0, mNotification.icon);
+        assertEquals(TICKER_TEXT, mNotification.tickerText);
+    }
+
+    public void testDescribeContents() {
+        final int expected = 0;
+        mNotification = new Notification();
+        assertEquals(expected, mNotification.describeContents());
+    }
+
+    public void testWriteToParcel() {
+        mNotification = new Notification();
+        mNotification.icon = 0;
+        mNotification.number = 1;
+        final Intent intent = new Intent();
+        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+        mNotification.contentIntent = pendingIntent;
+        final Intent deleteIntent = new Intent();
+        final PendingIntent delPendingIntent = PendingIntent.getBroadcast(
+                mContext, 0, deleteIntent, 0);
+        mNotification.deleteIntent = delPendingIntent;
+        mNotification.tickerText = TICKER_TEXT;
+
+        final RemoteViews contentView = new RemoteViews(mContext.getPackageName(),
+                android.R.layout.simple_list_item_1);
+        mNotification.contentView = contentView;
+        mNotification.defaults = 0;
+        mNotification.flags = 0;
+        final Uri uri = Uri.parse(URI_STRING);
+        mNotification.sound = uri;
+        mNotification.audioStreamType = 0;
+        final long[] longArray = { 1l, 2l, 3l };
+        mNotification.vibrate = longArray;
+        mNotification.ledARGB = 0;
+        mNotification.ledOnMS = 0;
+        mNotification.ledOffMS = 0;
+        mNotification.iconLevel = 0;
+        Parcel parcel = Parcel.obtain();
+        mNotification.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        // Test Notification(Parcel)
+        Notification result = new Notification(parcel);
+        assertEquals(mNotification.icon, result.icon);
+        assertEquals(mNotification.when, result.when);
+        assertEquals(mNotification.number, result.number);
+        assertNotNull(result.contentIntent);
+        assertNotNull(result.deleteIntent);
+        assertEquals(mNotification.tickerText, result.tickerText);
+        assertNotNull(result.contentView);
+        assertEquals(mNotification.defaults, result.defaults);
+        assertEquals(mNotification.flags, result.flags);
+        assertNotNull(result.sound);
+        assertEquals(mNotification.audioStreamType, result.audioStreamType);
+        assertEquals(mNotification.vibrate[0], result.vibrate[0]);
+        assertEquals(mNotification.vibrate[1], result.vibrate[1]);
+        assertEquals(mNotification.vibrate[2], result.vibrate[2]);
+        assertEquals(mNotification.ledARGB, result.ledARGB);
+        assertEquals(mNotification.ledOnMS, result.ledOnMS);
+        assertEquals(mNotification.ledOffMS, result.ledOffMS);
+        assertEquals(mNotification.iconLevel, result.iconLevel);
+
+        mNotification.contentIntent = null;
+        parcel = Parcel.obtain();
+        mNotification.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        result = new Notification(parcel);
+        assertNull(result.contentIntent);
+
+        mNotification.deleteIntent = null;
+        parcel = Parcel.obtain();
+        mNotification.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        result = new Notification(parcel);
+        assertNull(result.deleteIntent);
+
+        mNotification.tickerText = null;
+        parcel = Parcel.obtain();
+        mNotification.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        result = new Notification(parcel);
+        assertNull(result.tickerText);
+
+        mNotification.contentView = null;
+        parcel = Parcel.obtain();
+        mNotification.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        result = new Notification(parcel);
+        assertNull(result.contentView);
+
+        mNotification.sound = null;
+        parcel = Parcel.obtain();
+        mNotification.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        result = new Notification(parcel);
+        assertNull(result.sound);
+    }
+
+    public void testBuilder() {
+        final Intent intent = new Intent();
+        final PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+        mNotification = new Notification.Builder(mContext)
+                .setSmallIcon(1)
+                .setContentTitle(CONTENT_TITLE)
+                .setContentText(CONTENT_TEXT)
+                .setContentIntent(contentIntent)
+                .setTopic(new Topic("id1", "label1"))
+                .build();
+        assertEquals(CONTENT_TEXT, mNotification.extras.getString(Notification.EXTRA_TEXT));
+        assertEquals(CONTENT_TITLE, mNotification.extras.getString(Notification.EXTRA_TITLE));
+        assertEquals(1, mNotification.icon);
+        assertEquals(contentIntent, mNotification.contentIntent);
+        assertEquals(new Topic("id1", "label1"), mNotification.getTopic());
+    }
+
+    public void testWriteTopicToParcel() {
+        mNotification = new Notification.Builder(mContext)
+                .setTopic(new Topic("id2", "label2"))
+                .build();
+        Parcel parcel = Parcel.obtain();
+        mNotification.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        // Test Notification(Parcel)
+        Notification result = new Notification(parcel);
+        assertEquals(new Topic("id2", "label2"), result.getTopic());
+
+        mNotification = new Notification();
+        parcel = Parcel.obtain();
+        mNotification.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        // Test Notification(Parcel)
+        result = new Notification(parcel);
+        assertNull(result.getTopic());
+    }
+
+    public void testToString() {
+        mNotification = new Notification();
+        assertNotNull(mNotification.toString());
+    }
+}
diff --git a/tests/app/src/android/app/cts/OrientationTestUtils.java b/tests/app/src/android/app/cts/OrientationTestUtils.java
deleted file mode 100644
index 7b2b568..0000000
--- a/tests/app/src/android/app/cts/OrientationTestUtils.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.pm.ActivityInfo;
-
-public class OrientationTestUtils {
-
-    /**
-     * Change the activity's orientation to something different and then switch back. This is used
-     * to trigger {@link Activity#onConfigurationChanged(android.content.res.Configuration)}.
-     *
-     * @param activity whose orientation will be changed and restored
-     */
-    public static void toggleOrientation(Activity activity) {
-        toggleOrientationSync(activity, null);
-    }
-
-    /**
-     * Same as {@link #toggleOrientation(Activity)} except {@link Instrumentation#waitForIdleSync()}
-     * is called after each orientation change.
-     *
-     * @param activity whose orientation will be changed and restored
-     * @param instrumentation use for idle syncing
-     */
-    public static void toggleOrientationSync(final Activity activity,
-            final Instrumentation instrumentation) {
-        final int originalOrientation = activity.getResources().getConfiguration().orientation;
-        final int newOrientation = originalOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
-                ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
-                : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-        changeOrientation(activity, instrumentation, newOrientation);
-        changeOrientation(activity, instrumentation, originalOrientation);
-    }
-
-    private static void changeOrientation(final Activity activity,
-            Instrumentation instrumentation, final int orientation) {
-        activity.setRequestedOrientation(orientation);
-        if (instrumentation != null) {
-            instrumentation.waitForIdleSync();
-        }
-    }
-}
diff --git a/tests/app/src/android/app/cts/PendingIntentStubActivity.java b/tests/app/src/android/app/cts/PendingIntentStubActivity.java
deleted file mode 100644
index a2a3bd8..0000000
--- a/tests/app/src/android/app/cts/PendingIntentStubActivity.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class PendingIntentStubActivity extends Activity {
-
-    public static final int INVALIDATE = -1;
-    public static final int ON_CREATE = 0;
-    public static int status = INVALIDATE;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        status = ON_CREATE;
-    }
-
-}
diff --git a/tests/app/src/android/app/cts/PendingIntentTest.java b/tests/app/src/android/app/cts/PendingIntentTest.java
new file mode 100644
index 0000000..697de72
--- /dev/null
+++ b/tests/app/src/android/app/cts/PendingIntentTest.java
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.app.stubs.MockReceiver;
+import android.app.stubs.MockService;
+import android.app.stubs.PendingIntentStubActivity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+public class PendingIntentTest extends AndroidTestCase {
+
+    private static final int WAIT_TIME = 5000;
+    private PendingIntent mPendingIntent;
+    private Intent mIntent;
+    private Context mContext;
+    private boolean mFinishResult;
+    private boolean mHandleResult;
+    private String mResultAction;
+    private PendingIntent.OnFinished mFinish;
+    private boolean mLooperStart;
+    private Looper mLooper;
+    private Handler mHandler;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getContext();
+        mFinish = new PendingIntent.OnFinished() {
+            public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
+                    String resultData, Bundle resultExtras) {
+                mFinishResult = true;
+                if (intent != null) {
+                    mResultAction = intent.getAction();
+                }
+            }
+        };
+
+        new Thread() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                mLooper = Looper.myLooper();
+                mLooperStart = true;
+                Looper.loop();
+            }
+        }.start();
+        while (!mLooperStart) {
+            Thread.sleep(50);
+        }
+        mHandler = new Handler(mLooper) {
+            @Override
+            public void dispatchMessage(Message msg) {
+                mHandleResult = true;
+                super.dispatchMessage(msg);
+            }
+
+            @Override
+            public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+                mHandleResult = true;
+                return super.sendMessageAtTime(msg, uptimeMillis);
+            }
+
+            @Override
+            public void handleMessage(Message msg) {
+                super.handleMessage(msg);
+                mHandleResult = true;
+            }
+        };
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mLooper.quit();
+    }
+
+    public void testGetActivity() throws InterruptedException, CanceledException {
+        PendingIntentStubActivity.status = PendingIntentStubActivity.INVALIDATE;
+        mPendingIntent = null;
+        mIntent = new Intent();
+
+        mIntent.setClass(mContext, PendingIntentStubActivity.class);
+        mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+        assertEquals(mContext.getPackageName(), mPendingIntent.getTargetPackage());
+
+        mPendingIntent.send();
+
+        Thread.sleep(WAIT_TIME);
+        assertNotNull(mPendingIntent);
+        assertEquals(PendingIntentStubActivity.status, PendingIntentStubActivity.ON_CREATE);
+
+        // test getActivity return null
+        mPendingIntent.cancel();
+        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
+                PendingIntent.FLAG_NO_CREATE);
+        assertNull(mPendingIntent);
+
+        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
+                PendingIntent.FLAG_ONE_SHOT);
+
+        pendingIntentSendError(mPendingIntent);
+    }
+
+    private void pendingIntentSendError(PendingIntent pendingIntent) {
+        try {
+            // From the doc send function will throw CanceledException if the PendingIntent
+            // is no longer allowing more intents to be sent through it. So here call it twice then
+            // a CanceledException should be caught.
+            mPendingIntent.send();
+            mPendingIntent.send();
+            fail("CanceledException expected, but not thrown");
+        } catch (PendingIntent.CanceledException e) {
+            // expected
+        }
+    }
+
+    public void testGetBroadcast() throws InterruptedException, CanceledException {
+        MockReceiver.sAction = null;
+        mIntent = new Intent(MockReceiver.MOCKACTION);
+        mIntent.setClass(mContext, MockReceiver.class);
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+
+        mPendingIntent.send();
+
+        Thread.sleep(WAIT_TIME);
+        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
+
+        // test getBroadcast return null
+        mPendingIntent.cancel();
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
+                PendingIntent.FLAG_NO_CREATE);
+        assertNull(mPendingIntent);
+
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
+                PendingIntent.FLAG_ONE_SHOT);
+
+        pendingIntentSendError(mPendingIntent);
+    }
+
+    public void testGetService() throws InterruptedException, CanceledException {
+        MockService.result = false;
+        mIntent = new Intent();
+        mIntent.setClass(mContext, MockService.class);
+        mPendingIntent = PendingIntent.getService(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+
+        mPendingIntent.send();
+
+        Thread.sleep(WAIT_TIME);
+        assertTrue(MockService.result);
+
+        // test getService return null
+        mPendingIntent.cancel();
+        mPendingIntent = PendingIntent.getService(mContext, 1, mIntent,
+                PendingIntent.FLAG_NO_CREATE);
+        assertNull(mPendingIntent);
+
+        mPendingIntent = PendingIntent.getService(mContext, 1, mIntent,
+                PendingIntent.FLAG_ONE_SHOT);
+
+        pendingIntentSendError(mPendingIntent);
+    }
+
+    public void testCancel() throws CanceledException {
+        mIntent = new Intent();
+        mIntent.setClass(mContext, MockService.class);
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+
+        mPendingIntent.send();
+
+        mPendingIntent.cancel();
+        pendingIntentSendShouldFail(mPendingIntent);
+    }
+
+    private void pendingIntentSendShouldFail(PendingIntent pendingIntent) {
+        try {
+            pendingIntent.send();
+            fail("CanceledException expected, but not thrown");
+        } catch (CanceledException e) {
+            // expected
+        }
+    }
+
+    public void testSend() throws InterruptedException, CanceledException {
+        MockReceiver.sAction = null;
+        MockReceiver.sResultCode = -1;
+        mIntent = new Intent();
+        mIntent.setAction(MockReceiver.MOCKACTION);
+        mIntent.setClass(mContext, MockReceiver.class);
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+
+        mPendingIntent.send();
+
+        Thread.sleep(WAIT_TIME);
+
+        // send function to send default code 0
+        assertEquals(0, MockReceiver.sResultCode);
+        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
+        mPendingIntent.cancel();
+
+        pendingIntentSendShouldFail(mPendingIntent);
+    }
+
+    public void testSendWithParamInt() throws InterruptedException, CanceledException {
+        mIntent = new Intent(MockReceiver.MOCKACTION);
+        mIntent.setClass(mContext, MockReceiver.class);
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+        MockReceiver.sResultCode = 0;
+        MockReceiver.sAction = null;
+        // send result code 1.
+        mPendingIntent.send(1);
+        Thread.sleep(WAIT_TIME);
+        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
+
+        // assert the result code
+        assertEquals(1, MockReceiver.sResultCode);
+        assertEquals(mResultAction, null);
+
+        mResultAction = null;
+        MockReceiver.sResultCode = 0;
+        // send result code 2
+        mPendingIntent.send(2);
+        Thread.sleep(WAIT_TIME);
+
+        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
+
+        // assert the result code
+        assertEquals(2, MockReceiver.sResultCode);
+        assertEquals(MockReceiver.sAction, MockReceiver.MOCKACTION);
+        assertNull(mResultAction);
+        mPendingIntent.cancel();
+        pendingIntentSendShouldFail(mPendingIntent);
+    }
+
+    public void testSendWithParamContextIntIntent() throws InterruptedException, CanceledException {
+        mIntent = new Intent(MockReceiver.MOCKACTION);
+        mIntent.setClass(mContext, MockReceiver.class);
+
+        MockReceiver.sAction = null;
+        MockReceiver.sResultCode = 0;
+
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
+
+        mPendingIntent.send(mContext, 1, null);
+        Thread.sleep(WAIT_TIME);
+
+        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
+        assertEquals(1, MockReceiver.sResultCode);
+        mPendingIntent.cancel();
+
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
+        MockReceiver.sAction = null;
+        MockReceiver.sResultCode = 0;
+
+        mPendingIntent.send(mContext, 2, mIntent);
+        Thread.sleep(WAIT_TIME);
+        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
+        assertEquals(2, MockReceiver.sResultCode);
+        mPendingIntent.cancel();
+    }
+
+    public void testSendWithParamIntOnFinishedHandler() throws InterruptedException,
+            CanceledException {
+        mIntent = new Intent(MockReceiver.MOCKACTION);
+        mIntent.setClass(mContext, MockReceiver.class);
+
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
+        mFinishResult = false;
+        mHandleResult = false;
+        MockReceiver.sAction = null;
+        MockReceiver.sResultCode = 0;
+
+        mPendingIntent.send(1, null, null);
+        Thread.sleep(WAIT_TIME);
+        assertFalse(mFinishResult);
+        assertFalse(mHandleResult);
+        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
+
+        // assert result code
+        assertEquals(1, MockReceiver.sResultCode);
+        mPendingIntent.cancel();
+
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
+        mFinishResult = false;
+        MockReceiver.sAction = null;
+        MockReceiver.sResultCode = 0;
+        mHandleResult = false;
+
+        mPendingIntent.send(2, mFinish, null);
+        Thread.sleep(WAIT_TIME);
+        assertTrue(mFinishResult);
+        assertFalse(mHandleResult);
+        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
+
+        // assert result code
+        assertEquals(2, MockReceiver.sResultCode);
+        mPendingIntent.cancel();
+
+        mHandleResult = false;
+        mFinishResult = false;
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
+        MockReceiver.sAction = null;
+        mPendingIntent.send(3, mFinish, mHandler);
+        Thread.sleep(WAIT_TIME);
+        assertTrue(mHandleResult);
+        assertTrue(mFinishResult);
+        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
+
+        // assert result code
+        assertEquals(3, MockReceiver.sResultCode);
+        mPendingIntent.cancel();
+    }
+
+    public void testSendWithParamContextIntIntentOnFinishedHandler() throws InterruptedException,
+            CanceledException {
+        mIntent = new Intent(MockReceiver.MOCKACTION);
+        mIntent.setAction(MockReceiver.MOCKACTION);
+
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
+        mFinishResult = false;
+        mResultAction = null;
+        mHandleResult = false;
+        mPendingIntent.send(mContext, 1, mIntent, null, null);
+        Thread.sleep(WAIT_TIME);
+        assertFalse(mFinishResult);
+        assertFalse(mHandleResult);
+        assertNull(mResultAction);
+        mPendingIntent.cancel();
+
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
+        mFinishResult = false;
+        mResultAction = null;
+        mHandleResult = false;
+        mPendingIntent.send(mContext, 1, mIntent, mFinish, null);
+        Thread.sleep(WAIT_TIME);
+        assertTrue(mFinishResult);
+        assertEquals(mResultAction, MockReceiver.MOCKACTION);
+        assertFalse(mHandleResult);
+        mPendingIntent.cancel();
+
+        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
+        mFinishResult = false;
+        mResultAction = null;
+        mHandleResult = false;
+        mPendingIntent.send(mContext, 1, mIntent, mFinish, mHandler);
+        Thread.sleep(WAIT_TIME);
+        assertTrue(mHandleResult);
+        assertEquals(mResultAction, MockReceiver.MOCKACTION);
+        assertTrue(mFinishResult);
+        mPendingIntent.cancel();
+    }
+
+    public void testGetTargetPackage() {
+        mIntent = new Intent();
+        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+        assertEquals(mContext.getPackageName(), mPendingIntent.getTargetPackage());
+    }
+
+    public void testEquals() {
+        mIntent = new Intent();
+        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+
+        PendingIntent target = PendingIntent.getActivity(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+
+        assertFalse(mPendingIntent.equals(target));
+        assertFalse(mPendingIntent.hashCode() == target.hashCode());
+        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent, 1);
+
+        target = PendingIntent.getActivity(mContext, 1, mIntent, 1);
+        assertTrue(mPendingIntent.equals(target));
+
+        mIntent = new Intent(MockReceiver.MOCKACTION);
+        target = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
+        assertFalse(mPendingIntent.equals(target));
+        assertFalse(mPendingIntent.hashCode() == target.hashCode());
+
+        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent, 1);
+        target = PendingIntent.getActivity(mContext, 1, mIntent, 1);
+
+        assertTrue(mPendingIntent.equals(target));
+        assertEquals(mPendingIntent.hashCode(), target.hashCode());
+    }
+
+    public void testDescribeContents() {
+        mIntent = new Intent();
+        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+        final int expected = 0;
+        assertEquals(expected, mPendingIntent.describeContents());
+    }
+
+    public void testWriteToParcel() {
+        mIntent = new Intent();
+        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+        Parcel parcel = Parcel.obtain();
+
+        mPendingIntent.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        PendingIntent pendingIntent = PendingIntent.CREATOR.createFromParcel(parcel);
+        assertTrue(mPendingIntent.equals(pendingIntent));
+    }
+
+    public void testReadAndWritePendingIntentOrNullToParcel() {
+        mIntent = new Intent();
+        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+        assertNotNull(mPendingIntent.toString());
+
+        Parcel parcel = Parcel.obtain();
+        PendingIntent.writePendingIntentOrNullToParcel(mPendingIntent, parcel);
+        parcel.setDataPosition(0);
+        PendingIntent target = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
+        assertEquals(mPendingIntent, target);
+        assertEquals(mPendingIntent.getTargetPackage(), target.getTargetPackage());
+
+        mPendingIntent = null;
+        parcel = Parcel.obtain();
+        PendingIntent.writePendingIntentOrNullToParcel(mPendingIntent, parcel);
+        target = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
+        assertNull(target);
+    }
+
+}
diff --git a/tests/tests/app/src/android/app/cts/PendingIntent_CanceledExceptionTest.java b/tests/app/src/android/app/cts/PendingIntent_CanceledExceptionTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/cts/PendingIntent_CanceledExceptionTest.java
rename to tests/app/src/android/app/cts/PendingIntent_CanceledExceptionTest.java
diff --git a/tests/app/src/android/app/cts/PipActivityTest.java b/tests/app/src/android/app/cts/PipActivityTest.java
new file mode 100644
index 0000000..a553169
--- /dev/null
+++ b/tests/app/src/android/app/cts/PipActivityTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.cts;
+
+import android.app.Instrumentation;
+import android.app.stubs.PipActivity;
+import android.test.ActivityInstrumentationTestCase2;
+
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+
+public class PipActivityTest extends ActivityInstrumentationTestCase2<PipActivity> {
+
+    private Instrumentation mInstrumentation;
+    private PipActivity mActivity;
+
+    public PipActivityTest() {
+        super("android.app.stubs", PipActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+    }
+
+    public void testLaunchPipActivity() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                final boolean supportsPip =
+                        mActivity.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
+                if (supportsPip) {
+                    mActivity.enterPictureInPictureMode();
+                    assertTrue(mActivity.inMultiWindowMode());
+                    assertTrue(mActivity.inPictureInPictureMode());
+                } else {
+                    boolean pipSupportDisabled = false;
+                    try {
+                        mActivity.enterPictureInPictureMode();
+                    } catch (IllegalStateException e) {
+                        // Pip not supported
+                        pipSupportDisabled = true;
+                    }
+                    assertTrue(pipSupportDisabled);
+                    assertFalse(mActivity.inMultiWindowMode());
+                    assertFalse(mActivity.inPictureInPictureMode());
+                }
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+}
diff --git a/tests/app/src/android/app/cts/PipNotResizeableActivityTest.java b/tests/app/src/android/app/cts/PipNotResizeableActivityTest.java
new file mode 100644
index 0000000..4f7f63e
--- /dev/null
+++ b/tests/app/src/android/app/cts/PipNotResizeableActivityTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.cts;
+
+import android.app.Instrumentation;
+import android.app.stubs.PipNotResizeableActivity;
+import android.test.ActivityInstrumentationTestCase2;
+
+public class PipNotResizeableActivityTest
+        extends ActivityInstrumentationTestCase2<PipNotResizeableActivity> {
+
+        private Instrumentation mInstrumentation;
+        private PipNotResizeableActivity mActivity;
+
+        public PipNotResizeableActivityTest() {
+            super("android.app.stubs", PipNotResizeableActivity.class);
+        }
+
+        @Override
+        protected void setUp() throws Exception {
+            super.setUp();
+            mInstrumentation = getInstrumentation();
+            mActivity = getActivity();
+        }
+
+        public void testLaunchPipNotResizeableActivity() throws Throwable {
+            runTestOnUiThread(new Runnable() {
+                public void run() {
+                    boolean pipSupportDisabled = false;
+                    try {
+                        mActivity.enterPictureInPictureMode();
+                    } catch (IllegalStateException e) {
+                        // Pip not supported
+                        pipSupportDisabled = true;
+                    } catch (IllegalArgumentException e) {
+                        // Pip not supported
+                        pipSupportDisabled = true;
+                    }
+                    assertTrue(pipSupportDisabled);
+                    assertFalse(mActivity.inMultiWindowMode());
+                    assertFalse(mActivity.inPictureInPictureMode());
+                }
+            });
+            mInstrumentation.waitForIdleSync();
+        }
+    }
diff --git a/tests/app/src/android/app/cts/PipNotSupportedActivityTest.java b/tests/app/src/android/app/cts/PipNotSupportedActivityTest.java
new file mode 100644
index 0000000..245421a
--- /dev/null
+++ b/tests/app/src/android/app/cts/PipNotSupportedActivityTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.cts;
+
+import android.app.Instrumentation;
+import android.app.stubs.PipNotSupportedActivity;
+import android.test.ActivityInstrumentationTestCase2;
+
+public class PipNotSupportedActivityTest
+        extends ActivityInstrumentationTestCase2<PipNotSupportedActivity> {
+
+    private Instrumentation mInstrumentation;
+    private PipNotSupportedActivity mActivity;
+
+    public PipNotSupportedActivityTest() {
+        super("android.app.stubs", PipNotSupportedActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+    }
+
+    public void testLaunchPipNotSupportedActivity() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                boolean pipSupportDisabled = false;
+                try {
+                    mActivity.enterPictureInPictureMode();
+                } catch (IllegalStateException e) {
+                    // Pip not supported
+                    pipSupportDisabled = true;
+                } catch (IllegalArgumentException e) {
+                    // Pip not supported
+                    pipSupportDisabled = true;
+                }
+                assertTrue(pipSupportDisabled);
+                assertFalse(mActivity.inMultiWindowMode());
+                assertFalse(mActivity.inPictureInPictureMode());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+}
diff --git a/tests/app/src/android/app/cts/ProgressDialogTest.java b/tests/app/src/android/app/cts/ProgressDialogTest.java
new file mode 100644
index 0000000..4f4007e
--- /dev/null
+++ b/tests/app/src/android/app/cts/ProgressDialogTest.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Instrumentation;
+import android.app.ProgressDialog;
+import android.app.stubs.MockActivity;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.view.Window;
+import android.widget.ProgressBar;
+
+import android.app.stubs.R;
+
+/**
+ * Test {@link ProgressDialog}.
+ */
+public class ProgressDialogTest extends ActivityInstrumentationTestCase2<MockActivity> {
+    private final CharSequence TITLE = "title";
+    private final CharSequence MESSAGE = "message";
+
+    private boolean mCanceled;
+    private Drawable mDrawable;
+    private Drawable mActualDrawableNull;
+    private Drawable mActualDrawable;
+    private ProgressBar mProgressBar;
+    private int mProgress1;
+    private int mProgress2;
+
+    private Context mContext;
+    private Instrumentation mInstrumentation;
+    private MockActivity mActivity;
+
+    public ProgressDialogTest() {
+        super("android.app.stubs", MockActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mCanceled = false;
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+        mContext = mActivity;
+        mDrawable = getActivity().getResources().getDrawable(
+                R.drawable.yellow);
+    }
+
+    @UiThreadTest
+    public void testProgressDialog1(){
+        new ProgressDialog(mContext);
+    }
+
+    @UiThreadTest
+    public void testProgressDialog2(){
+        new ProgressDialog(mContext, R.style.Theme_AlertDialog);
+    }
+
+    @UiThreadTest
+    public void testOnStartCreateStop() {
+        MockProgressDialog pd = new MockProgressDialog(mContext);
+
+        assertFalse(pd.mIsOnCreateCalled);
+        assertFalse(pd.mIsOnStartCalled);
+        pd.show();
+        assertTrue(pd.mIsOnCreateCalled);
+        assertTrue(pd.mIsOnStartCalled);
+
+        assertFalse(pd.mIsOnStopCalled);
+        pd.dismiss();
+        assertTrue(pd.mIsOnStopCalled);
+    }
+
+    @UiThreadTest
+    public void testShow1() {
+        ProgressDialog.show(mContext, TITLE, MESSAGE);
+    }
+
+    @UiThreadTest
+    public void testShow2() {
+        ProgressDialog dialog = ProgressDialog.show(mContext, TITLE, MESSAGE, false);
+
+        /*
+         * note: the progress bar's style only supports indeterminate mode,
+         * so can't change indeterminate
+         */
+        assertTrue(dialog.isIndeterminate());
+
+        dialog = ProgressDialog.show(mContext, TITLE, MESSAGE, true);
+        assertTrue(dialog.isIndeterminate());
+    }
+
+    public void testShow3() throws Throwable {
+        final OnCancelListener cL = new OnCancelListener(){
+            public void onCancel(DialogInterface dialog) {
+                mCanceled = true;
+            }
+        };
+
+        // cancelable is false
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                ProgressDialog dialog = ProgressDialog.show(mContext, TITLE, MESSAGE, true, false);
+
+                dialog.setOnCancelListener(cL);
+                dialog.onBackPressed();
+                dialog.dismiss();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertFalse(mCanceled);
+
+        // cancelable is true
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                ProgressDialog dialog = ProgressDialog.show(mContext, TITLE, MESSAGE, true, true);
+                assertFalse(mCanceled);
+                dialog.setOnCancelListener(cL);
+                dialog.onBackPressed();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(mCanceled);
+    }
+
+    public void testShow4() throws Throwable {
+        final OnCancelListener cL = new OnCancelListener(){
+            public void onCancel(DialogInterface dialog) {
+                mCanceled = true;
+            }
+        };
+
+        // cancelable is false
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                ProgressDialog dialog = ProgressDialog.show(
+                        mContext, TITLE, MESSAGE, true, false, cL);
+
+                dialog.onBackPressed();
+                dialog.dismiss();;
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertFalse(mCanceled);
+
+        // cancelable is true
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                ProgressDialog dialog = ProgressDialog.show(
+                        mContext, TITLE, MESSAGE, true, true, cL);
+
+                assertFalse(mCanceled);
+                dialog.onBackPressed();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(mCanceled);
+    }
+
+    @UiThreadTest
+    public void testAccessMax() {
+        // progressDialog is null
+        ProgressDialog progressDialog = buildDialog();
+        progressDialog.setMax(2008);
+        assertEquals(2008, progressDialog.getMax());
+
+        // progressDialog is not null
+        progressDialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
+        progressDialog.setMax(2009);
+        assertEquals(2009, progressDialog.getMax());
+    }
+
+    @UiThreadTest
+    public void testAccessProgress() {
+        // progressDialog is null
+        ProgressDialog progressDialog = buildDialog();
+        progressDialog.setProgress(11);
+        assertEquals(11, progressDialog.getProgress());
+
+        /* progressDialog is not null
+         * note: the progress bar's style only supports indeterminate mode,
+         * so can't change progress
+         */
+        progressDialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
+        progressDialog.setProgress(12);
+        assertEquals(0, progressDialog.getProgress());
+    }
+
+    @UiThreadTest
+    public void testAccessSecondaryProgress() {
+        // dialog is null
+        ProgressDialog dialog = buildDialog();
+        dialog.setSecondaryProgress(17);
+        assertEquals(17, dialog.getSecondaryProgress());
+
+        /* mProgress is not null
+         * note: the progress bar's style only supports indeterminate mode,
+         * so can't change secondary progress
+         */
+        dialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
+        dialog.setSecondaryProgress(18);
+        assertEquals(0, dialog.getSecondaryProgress());
+    }
+
+    @UiThreadTest
+    public void testSetIndeterminate() {
+        // progress is null
+        ProgressDialog dialog = buildDialog();
+        dialog.setIndeterminate(true);
+        assertTrue(dialog.isIndeterminate());
+        dialog.setIndeterminate(false);
+        assertFalse(dialog.isIndeterminate());
+
+        /* mProgress is not null
+         * note: the progress bar's style only supports indeterminate mode,
+         * so can't change indeterminate
+         */
+        dialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
+        dialog.setIndeterminate(true);
+        assertTrue(dialog.isIndeterminate());
+        dialog.setIndeterminate(false);
+        assertTrue(dialog.isIndeterminate());
+    }
+
+    @UiThreadTest
+    public void testIncrementProgressBy() throws Throwable {
+        ProgressDialog dialog = new ProgressDialog(mContext);
+        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+        dialog.show();
+        dialog.setProgress(10);
+        mProgress1 = dialog.getProgress();
+        dialog.incrementProgressBy(60);
+        mProgress2 = dialog.getProgress();
+        dialog.cancel();
+
+        assertEquals(10, mProgress1);
+        assertEquals(70, mProgress2);
+    }
+
+    @UiThreadTest
+    public void testIncrementSecondaryProgressBy() throws Throwable {
+        ProgressDialog dialog = new ProgressDialog(mContext);
+        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+        dialog.show();
+        dialog.setSecondaryProgress(10);
+        mProgress1 = dialog.getSecondaryProgress();
+        dialog.incrementSecondaryProgressBy(60);
+        mProgress2 = dialog.getSecondaryProgress();
+
+        assertEquals(10, mProgress1);
+        assertEquals(70, mProgress2);
+    }
+
+    @UiThreadTest
+    public void testSetProgressDrawable() throws Throwable {
+        ProgressDialog dialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
+        Window w = dialog.getWindow();
+        ProgressBar progressBar = (ProgressBar) w.findViewById(android.R.id.progress);
+
+        dialog.setProgressDrawable(mDrawable);
+        mActualDrawable = progressBar.getProgressDrawable();
+
+        dialog.setProgressDrawable(null);
+        mActualDrawableNull = progressBar.getProgressDrawable();
+        assertEquals(mDrawable, mActualDrawable);
+        assertEquals(null, mActualDrawableNull);
+    }
+
+    @UiThreadTest
+    public void testSetIndeterminateDrawable() throws Throwable {
+        ProgressDialog dialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
+        Window w = dialog.getWindow();
+        mProgressBar = (ProgressBar) w.findViewById(android.R.id.progress);
+
+        dialog.setIndeterminateDrawable(mDrawable);
+        mActualDrawable = mProgressBar.getIndeterminateDrawable();
+        assertEquals(mDrawable, mActualDrawable);
+
+        dialog.setIndeterminateDrawable(null);
+        mActualDrawableNull = mProgressBar.getIndeterminateDrawable();
+        assertEquals(null, mActualDrawableNull);
+    }
+
+    @UiThreadTest
+    public void testSetMessage() throws Throwable {
+        ProgressDialog dialog = new ProgressDialog(mContext);
+        dialog = new ProgressDialog(mContext);
+        dialog.setMessage(MESSAGE);
+        dialog.show();
+        // dialog is not null
+        dialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
+        dialog.setMessage("Chuck Norris");
+    }
+
+    @UiThreadTest
+    public void testSetProgressStyle() throws Throwable {
+        ProgressDialog dialog = new ProgressDialog(mContext);
+        setProgressStyle(dialog, ProgressDialog.STYLE_HORIZONTAL);
+        setProgressStyle(dialog, ProgressDialog.STYLE_SPINNER);
+        setProgressStyle(dialog, 100);
+    }
+
+    private void setProgressStyle(ProgressDialog dialog, int style) {
+        dialog.setProgressStyle(style);
+        dialog.show();
+        dialog.setProgress(10);
+        dialog.setMax(100);
+    }
+
+    private static class MockProgressDialog extends ProgressDialog {
+        public boolean mIsOnStopCalled;
+        public boolean mIsOnStartCalled;
+        public boolean mIsOnCreateCalled;
+
+        public MockProgressDialog(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mIsOnCreateCalled = true;
+        }
+
+        @Override
+        public void onStart(){
+            super.onStart();
+            mIsOnStartCalled = true;
+        }
+
+        @Override
+        public void onStop() {
+            super.onStop();
+            mIsOnStopCalled = true;
+        }
+    }
+
+    private ProgressDialog buildDialog() {
+        return new ProgressDialog(mContext);
+    }
+}
diff --git a/tests/app/src/android/app/cts/SearchManagerStubActivity.java b/tests/app/src/android/app/cts/SearchManagerStubActivity.java
deleted file mode 100644
index 0dbd832..0000000
--- a/tests/app/src/android/app/cts/SearchManagerStubActivity.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.app.SearchManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.cts.util.CTSResult;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-public class SearchManagerStubActivity extends Activity {
-
-    private static final String TAG = "SearchManagerStubActivity";
-
-    public static final String TEST_STOP_SEARCH = "stopSearch";
-    public static final String TEST_ON_DISMISSLISTENER = "setOnDismissListener";
-    public static final String TEST_ON_CANCELLISTENER = "setOnCancelListener";
-
-    private SearchManager mSearchManager;
-    private ComponentName mComponentName;
-
-    private static CTSResult sCTSResult;
-    private boolean mDismissCalled;
-    private boolean mCancelCalled;
-
-    public static void setCTSResult(CTSResult result) {
-        sCTSResult = result;
-    }
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        mSearchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
-        mComponentName = getComponentName();
-        String action = getIntent().getAction();
-        if (action.equals(TEST_STOP_SEARCH)) {
-            testStopSearch();
-        } else if (action.equals(TEST_ON_DISMISSLISTENER)) {
-            testOnDismissListener();
-        } else if (action.equals(TEST_ON_CANCELLISTENER)) {
-            testOnCancelListener();
-        }
-    }
-
-    private void testOnCancelListener() {
-        mCancelCalled = false;
-        mSearchManager.setOnCancelListener(new SearchManager.OnCancelListener() {
-            @Override
-            public void onCancel() {
-               mCancelCalled = true;
-            }
-        });
-
-        new TestStepHandler() {
-            @Override
-            public boolean doStep(int step) throws FailException {
-                switch (step) {
-                    case 1:
-                        startSearch("test", false, mComponentName, null, false);
-                        return false;
-                    case 2:
-                        assertFalse("cancel called", mCancelCalled);
-                        stopSearch();
-                        return false;
-                    case 3:
-                        assertTrue("cancel not called", mCancelCalled);
-                        pass();
-                        return true;
-                    default:
-                        throw new IllegalArgumentException("Bad step " + step);
-                }
-            }
-        }.start();
-    }
-
-    private void testOnDismissListener() {
-        mDismissCalled = false;
-
-        mSearchManager.setOnDismissListener(new SearchManager.OnDismissListener() {
-            public void onDismiss() {
-                mDismissCalled = true;
-            }
-        });
-
-        new TestStepHandler() {
-            @Override
-            public boolean doStep(int step) throws FailException {
-                switch (step) {
-                    case 1:
-                        startSearch("test", false, mComponentName, null, false);
-                        return false;
-                    case 2:
-                        if (mDismissCalled) {
-                            throw new FailException("dismiss called");
-                        } else {
-                            stopSearch();
-                        }
-                        return false;
-                    case 3:
-                        if (mDismissCalled) {
-                            pass();
-                        } else {
-                            throw new FailException("dismiss not called");
-                        }
-                        return true;
-                    default:
-                        throw new IllegalArgumentException("Bad step " + step);
-                }
-            }
-        }.start();
-    }
-
-    private void testStopSearch() {
-        new TestStepHandler() {
-            @Override
-            public boolean doStep(int step) throws FailException {
-                switch (step) {
-                    case 1:
-                        startSearch("test", false, mComponentName, null, false);
-                        return false;
-                    case 2:
-                        assertVisible();
-                        stopSearch();
-                        return false;
-                    case 3:
-                        assertInVisible();
-                        pass();
-                        return true;
-                    default:
-                        throw new IllegalArgumentException("Bad step " + step);
-                }
-            }
-        }.start();
-    }
-
-    private void fail(Exception ex) {
-        Log.e(TAG, "test failed", ex);
-        sCTSResult.setResult(CTSResult.RESULT_FAIL);
-        finish();
-    }
-
-    private void pass() {
-        sCTSResult.setResult(CTSResult.RESULT_OK);
-        finish();
-    }
-
-    private void assertInVisible() throws FailException {
-        if (isVisible()) {
-            throw new FailException();
-        }
-    }
-
-    private void assertVisible() throws FailException {
-        if (!isVisible()) {
-            throw new FailException();
-        }
-    }
-
-    private void assertFalse(String message, boolean value) throws FailException {
-        assertTrue(message, !value);
-    }
-
-    private void assertTrue(String message, boolean value) throws FailException {
-        if (!value) {
-            throw new FailException(message);
-        }
-    }
-
-    private void startSearch(String initialQuery, boolean selectInitialQuery,
-            ComponentName launchActivity, Bundle appSearchData, boolean globalSearch) {
-        mSearchManager.startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData,
-                globalSearch);
-    }
-
-    private void stopSearch() {
-       mSearchManager.stopSearch();
-    }
-
-    private boolean isVisible() {
-        return mSearchManager.isVisible();
-    }
-
-    private abstract class TestStepHandler extends Handler {
-
-        public void start() {
-            sendEmptyMessage(1);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            try {
-                if (!doStep(msg.what)) {
-                    sendEmptyMessage(msg.what + 1);
-                }
-            } catch (FailException ex) {
-                fail(ex);
-            }
-        }
-
-        /**
-         * Performs one step of the test.
-         *
-         * @param step The 1-based number of the step to perform.
-         * @return {@code true} if this was the last step.
-         * @throws FailException If the test failed.
-         */
-        protected abstract boolean doStep(int step) throws FailException;
-    }
-
-    private static class FailException extends Exception {
-        private static final long serialVersionUID = 1L;
-
-        public FailException() {
-            super();
-        }
-
-        public FailException(String detailMessage) {
-            super(detailMessage);
-        }
-    }
-}
diff --git a/tests/app/src/android/app/cts/SearchManagerTest.java b/tests/app/src/android/app/cts/SearchManagerTest.java
new file mode 100644
index 0000000..00ba5e7
--- /dev/null
+++ b/tests/app/src/android/app/cts/SearchManagerTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.stubs.CTSActivityTestCaseBase;
+import android.app.stubs.SearchManagerStubActivity;
+import android.content.Intent;
+
+public class SearchManagerTest extends CTSActivityTestCaseBase {
+
+    private void setupActivity(String action) {
+        Intent intent = new Intent();
+        intent.setAction(action);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClass(getInstrumentation().getTargetContext(), SearchManagerStubActivity.class);
+        getInstrumentation().getTargetContext().startActivity(intent);
+    }
+
+    public void testStopSearch() throws InterruptedException {
+        SearchManagerStubActivity.setCTSResult(this);
+        setupActivity(SearchManagerStubActivity.TEST_STOP_SEARCH);
+        waitForResult();
+    }
+
+    public void testSetOnDismissListener() throws InterruptedException {
+        SearchManagerStubActivity.setCTSResult(this);
+        setupActivity(SearchManagerStubActivity.TEST_ON_DISMISSLISTENER);
+        waitForResult();
+    }
+
+    public void testSetOnCancelListener() throws InterruptedException {
+        SearchManagerStubActivity.setCTSResult(this);
+        setupActivity(SearchManagerStubActivity.TEST_ON_CANCELLISTENER);
+        waitForResult();
+    }
+}
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
new file mode 100644
index 0000000..4842bb1
--- /dev/null
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.stubs.ActivityTestsBase;
+import android.app.stubs.LocalDeniedService;
+import android.app.stubs.LocalGrantedService;
+import android.app.stubs.LocalService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.cts.util.IBinderParcelable;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class ServiceTest extends ActivityTestsBase {
+    private static final int STATE_START_1 = 0;
+    private static final int STATE_START_2 = 1;
+    private static final int STATE_UNBIND = 2;
+    private static final int STATE_DESTROY = 3;
+    private static final int STATE_REBIND = 4;
+    private static final int STATE_UNBIND_ONLY = 5;
+    private static final int DELAY = 5000;
+    private static final
+        String EXIST_CONN_TO_RECEIVE_SERVICE = "existing connection to receive service";
+    private static final String EXIST_CONN_TO_LOSE_SERVICE = "existing connection to lose service";
+    private int mExpectedServiceState;
+    private Context mContext;
+    private Intent mLocalService;
+    private Intent mLocalDeniedService;
+    private Intent mLocalGrantedService;
+    private Intent mLocalService_ApplicationHasPermission;
+    private Intent mLocalService_ApplicationDoesNotHavePermission;
+
+    private IBinder mStateReceiver;
+
+    private static class EmptyConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    }
+
+    private class TestConnection implements ServiceConnection {
+        private final boolean mExpectDisconnect;
+        private final boolean mSetReporter;
+        private boolean mMonitor;
+        private int mCount;
+
+        public TestConnection(boolean expectDisconnect, boolean setReporter) {
+            mExpectDisconnect = expectDisconnect;
+            mSetReporter = setReporter;
+            mMonitor = !setReporter;
+        }
+
+        void setMonitor(boolean v) {
+            mMonitor = v;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (mSetReporter) {
+                Parcel data = Parcel.obtain();
+                data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
+                data.writeStrongBinder(mStateReceiver);
+                try {
+                    service.transact(LocalService.SET_REPORTER_CODE, data, null, 0);
+                } catch (RemoteException e) {
+                    finishBad("DeadObjectException when sending reporting object");
+                }
+                data.recycle();
+            }
+
+            if (mMonitor) {
+                mCount++;
+                if (mExpectedServiceState == STATE_START_1) {
+                    if (mCount == 1) {
+                        finishGood();
+                    } else {
+                        finishBad("onServiceConnected() again on an object when it "
+                                + "should have been the first time");
+                    }
+                } else if (mExpectedServiceState == STATE_START_2) {
+                    if (mCount == 2) {
+                        finishGood();
+                    } else {
+                        finishBad("onServiceConnected() the first time on an object "
+                                + "when it should have been the second time");
+                    }
+                } else {
+                    finishBad("onServiceConnected() called unexpectedly");
+                }
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (mMonitor) {
+                if (mExpectedServiceState == STATE_DESTROY) {
+                    if (mExpectDisconnect) {
+                        finishGood();
+                    } else {
+                        finishBad("onServiceDisconnected() when it shouldn't have been");
+                    }
+                } else {
+                    finishBad("onServiceDisconnected() called unexpectedly");
+                }
+            }
+        }
+    }
+
+    private void startExpectResult(Intent service) {
+        startExpectResult(service, new Bundle());
+    }
+
+    private void startExpectResult(Intent service, Bundle bundle) {
+        bundle.putParcelable(LocalService.REPORT_OBJ_NAME, new IBinderParcelable(mStateReceiver));
+
+        boolean success = false;
+        try {
+            mExpectedServiceState = STATE_START_1;
+            mContext.startService(new Intent(service).putExtras(bundle));
+            waitForResultOrThrow(DELAY, "service to start first time");
+            mExpectedServiceState = STATE_START_2;
+            mContext.startService(new Intent(service).putExtras(bundle));
+            waitForResultOrThrow(DELAY, "service to start second time");
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.stopService(service);
+            }
+        }
+        mExpectedServiceState = STATE_DESTROY;
+        mContext.stopService(service);
+        waitForResultOrThrow(DELAY, "service to be destroyed");
+    }
+
+    /**
+     * test the service lifecycle, a service can be used in two ways:
+     * 1  It can be started and allowed to run until someone stops it or it stops itself.
+     *    In this mode, it's started by calling Context.startService()
+     *    and stopped by calling Context.stopService().
+     *    It can stop itself by calling Service.stopSelf() or Service.stopSelfResult().
+     *    Only one stopService() call is needed to stop the service,
+     *    no matter how many times startService() was called.
+     * 2  It can be operated programmatically using an interface that it defines and exports.
+     *    Clients establish a connection to the Service object
+     *    and use that connection to call into the service.
+     *    The connection is established by calling Context.bindService(),
+     *    and is closed by calling Context.unbindService().
+     *    Multiple clients can bind to the same service.
+     *    If the service has not already been launched, bindService() can optionally launch it.
+     */
+    private void bindExpectResult(Intent service) {
+        TestConnection conn = new TestConnection(true, false);
+        TestConnection conn2 = new TestConnection(false, false);
+        boolean success = false;
+        try {
+            // Expect to see the TestConnection connected.
+            mExpectedServiceState = STATE_START_1;
+            mContext.bindService(service, conn, 0);
+            mContext.startService(service);
+            waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
+
+            // Expect to see the second TestConnection connected.
+            mContext.bindService(service, conn2, 0);
+            waitForResultOrThrow(DELAY, "new connection to receive service");
+
+            mContext.unbindService(conn2);
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.unbindService(conn);
+                mContext.unbindService(conn2);
+                mContext.stopService(service);
+            }
+        }
+
+        // Expect to see the TestConnection disconnected.
+        mExpectedServiceState = STATE_DESTROY;
+        mContext.stopService(service);
+        waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
+
+        mContext.unbindService(conn);
+
+        conn = new TestConnection(true, true);
+        success = false;
+        try {
+            // Expect to see the TestConnection connected.
+            conn.setMonitor(true);
+            mExpectedServiceState = STATE_START_1;
+            mContext.bindService(service, conn, 0);
+            mContext.startService(service);
+            waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
+
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.unbindService(conn);
+                mContext.stopService(service);
+            }
+        }
+
+        // Expect to see the service unbind and then destroyed.
+        conn.setMonitor(false);
+        mExpectedServiceState = STATE_UNBIND;
+        mContext.stopService(service);
+        waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
+
+        mContext.unbindService(conn);
+
+        conn = new TestConnection(true, true);
+        success = false;
+        try {
+            // Expect to see the TestConnection connected.
+            conn.setMonitor(true);
+            mExpectedServiceState = STATE_START_1;
+            mContext.bindService(service, conn, 0);
+            mContext.startService(service);
+            waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
+
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.unbindService(conn);
+                mContext.stopService(service);
+            }
+        }
+
+        // Expect to see the service unbind but not destroyed.
+        conn.setMonitor(false);
+        mExpectedServiceState = STATE_UNBIND_ONLY;
+        mContext.unbindService(conn);
+        waitForResultOrThrow(DELAY, "existing connection to unbind service");
+
+        // Expect to see the service rebound.
+        mExpectedServiceState = STATE_REBIND;
+        mContext.bindService(service, conn, 0);
+        waitForResultOrThrow(DELAY, "existing connection to rebind service");
+
+        // Expect to see the service unbind and then destroyed.
+        mExpectedServiceState = STATE_UNBIND;
+        mContext.stopService(service);
+        waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
+
+        mContext.unbindService(conn);
+    }
+
+    /**
+     * test automatically create the service as long as the binding exists
+     * and disconnect from an application service
+     */
+    private void bindAutoExpectResult(Intent service) {
+        TestConnection conn = new TestConnection(false, true);
+        boolean success = false;
+        try {
+            conn.setMonitor(true);
+            mExpectedServiceState = STATE_START_1;
+            mContext.bindService(
+                    service, conn, Context.BIND_AUTO_CREATE);
+            waitForResultOrThrow(DELAY, "connection to start and receive service");
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.unbindService(conn);
+            }
+        }
+        mExpectedServiceState = STATE_UNBIND;
+        mContext.unbindService(conn);
+        waitForResultOrThrow(DELAY, "disconnecting from service");
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getContext();
+        mLocalService = new Intent(mContext, LocalService.class);
+        mLocalDeniedService = new Intent(mContext, LocalDeniedService.class);
+        mLocalGrantedService = new Intent(mContext, LocalGrantedService.class);
+        mLocalService_ApplicationHasPermission = new Intent(
+                LocalService.SERVICE_LOCAL_GRANTED, null /*uri*/, mContext, LocalService.class);
+        mLocalService_ApplicationDoesNotHavePermission = new Intent(
+                LocalService.SERVICE_LOCAL_DENIED, null /*uri*/, mContext, LocalService.class);
+        mStateReceiver = new MockBinder();
+    }
+
+    private class MockBinder extends Binder {
+        @Override
+        protected boolean onTransact(int code, Parcel data, Parcel reply,
+                int flags) throws RemoteException {
+            if (code == LocalService.STARTED_CODE) {
+                data.enforceInterface(LocalService.SERVICE_LOCAL);
+                int count = data.readInt();
+                if (mExpectedServiceState == STATE_START_1) {
+                    if (count == 1) {
+                        finishGood();
+                    } else {
+                        finishBad("onStart() again on an object when it "
+                                + "should have been the first time");
+                    }
+                } else if (mExpectedServiceState == STATE_START_2) {
+                    if (count == 2) {
+                        finishGood();
+                    } else {
+                        finishBad("onStart() the first time on an object when it "
+                                + "should have been the second time");
+                    }
+                } else {
+                    finishBad("onStart() was called when not expected (state="
+                            + mExpectedServiceState + ")");
+                }
+                return true;
+            } else if (code == LocalService.DESTROYED_CODE) {
+                data.enforceInterface(LocalService.SERVICE_LOCAL);
+                if (mExpectedServiceState == STATE_DESTROY) {
+                    finishGood();
+                } else {
+                    finishBad("onDestroy() was called when not expected (state="
+                            + mExpectedServiceState + ")");
+                }
+                return true;
+            } else if (code == LocalService.UNBIND_CODE) {
+                data.enforceInterface(LocalService.SERVICE_LOCAL);
+                if (mExpectedServiceState == STATE_UNBIND) {
+                    mExpectedServiceState = STATE_DESTROY;
+                } else if (mExpectedServiceState == STATE_UNBIND_ONLY) {
+                    finishGood();
+                } else {
+                    finishBad("onUnbind() was called when not expected (state="
+                            + mExpectedServiceState + ")");
+                }
+                return true;
+            } else if (code == LocalService.REBIND_CODE) {
+                data.enforceInterface(LocalService.SERVICE_LOCAL);
+                if (mExpectedServiceState == STATE_REBIND) {
+                    finishGood();
+                } else {
+                    finishBad("onRebind() was called when not expected (state="
+                            + mExpectedServiceState + ")");
+                }
+                return true;
+            } else {
+                return super.onTransact(code, data, reply, flags);
+            }
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mContext.stopService(mLocalService);
+        mContext.stopService(mLocalGrantedService);
+        mContext.stopService(mLocalService_ApplicationHasPermission);
+    }
+
+    public void testLocalStartClass() throws Exception {
+        startExpectResult(mLocalService);
+    }
+
+    public void testLocalStartAction() throws Exception {
+        startExpectResult(new Intent(
+                LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
+    }
+
+    public void testLocalBindClass() throws Exception {
+        bindExpectResult(mLocalService);
+    }
+
+    @MediumTest
+    public void testLocalBindAction() throws Exception {
+        bindExpectResult(new Intent(
+                LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
+    }
+
+    @MediumTest
+    public void testLocalBindAutoClass() throws Exception {
+        bindAutoExpectResult(mLocalService);
+    }
+
+    @MediumTest
+    public void testLocalBindAutoAction() throws Exception {
+        bindAutoExpectResult(new Intent(
+                LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
+    }
+
+    @MediumTest
+    public void testLocalStartClassPermissions() throws Exception {
+        startExpectResult(mLocalGrantedService);
+        startExpectResult(mLocalDeniedService);
+    }
+
+    @MediumTest
+    public void testLocalStartActionPermissions() throws Exception {
+        startExpectResult(mLocalService_ApplicationHasPermission);
+        startExpectResult(mLocalService_ApplicationDoesNotHavePermission);
+    }
+
+    @MediumTest
+    public void testLocalBindClassPermissions() throws Exception {
+        bindExpectResult(mLocalGrantedService);
+        bindExpectResult(mLocalDeniedService);
+    }
+
+    @MediumTest
+    public void testLocalBindActionPermissions() throws Exception {
+        bindExpectResult(mLocalService_ApplicationHasPermission);
+        bindExpectResult(mLocalService_ApplicationDoesNotHavePermission);
+    }
+
+    @MediumTest
+    public void testLocalBindAutoClassPermissionGranted() throws Exception {
+        bindAutoExpectResult(mLocalGrantedService);
+    }
+
+    @MediumTest
+    public void testLocalBindAutoActionPermissionGranted() throws Exception {
+        bindAutoExpectResult(mLocalService_ApplicationHasPermission);
+    }
+
+    @MediumTest
+    public void testLocalUnbindTwice() throws Exception {
+        EmptyConnection conn = new EmptyConnection();
+        mContext.bindService(
+                mLocalService_ApplicationHasPermission, conn, 0);
+        mContext.unbindService(conn);
+        try {
+            mContext.unbindService(conn);
+            fail("No exception thrown on the second unbind");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @MediumTest
+    public void testImplicitIntentFailsOnApiLevel21() throws Exception {
+        Intent intent = new Intent(LocalService.SERVICE_LOCAL);
+        EmptyConnection conn = new EmptyConnection();
+        try {
+            mContext.bindService(intent, conn, 0);
+            mContext.unbindService(conn);
+            fail("Implicit intents should be disallowed for apps targeting API 21+");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+}
diff --git a/tests/app/src/android/app/cts/StubRemoteService.java b/tests/app/src/android/app/cts/StubRemoteService.java
deleted file mode 100644
index 1239734..0000000
--- a/tests/app/src/android/app/cts/StubRemoteService.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-import android.os.Process;
-
-public class StubRemoteService extends Service{
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        android.util.Log.d("Process test stub", "StubRemoteServiceProcessPid:" + Process.myPid());
-    }
-
-    private final ISecondary.Stub mSecondaryBinder = new ISecondary.Stub() {
-        public int getPid() {
-            return Process.myPid();
-        }
-
-        public long getElapsedCpuTime() {
-            return Process.getElapsedCpuTime();
-        }
-
-        public String getTimeZoneID() {
-            return java.util.TimeZone.getDefault().getID();
-        }
-    };
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        if (ISecondary.class.getName().equals(intent.getAction())) {
-            return mSecondaryBinder;
-        }
-        return null;
-    }
-
-}
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
new file mode 100644
index 0000000..028ca89
--- /dev/null
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -0,0 +1,503 @@
+/*
+ * 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.
+ */
+
+package android.app.cts;
+
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.app.WallpaperManager;
+import android.bluetooth.BluetoothAdapter;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
+import android.hardware.Camera.Parameters;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
+import android.location.LocationManager;
+import android.net.sip.SipManager;
+import android.net.wifi.WifiManager;
+import android.nfc.NfcAdapter;
+import android.telephony.TelephonyManager;
+import android.test.InstrumentationTestCase;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Test for checking that the {@link PackageManager} is reporting the correct features.
+ */
+public class SystemFeaturesTest extends InstrumentationTestCase {
+
+    private Context mContext;
+    private PackageManager mPackageManager;
+    private HashSet<String> mAvailableFeatures;
+
+    private ActivityManager mActivityManager;
+    private LocationManager mLocationManager;
+    private SensorManager mSensorManager;
+    private TelephonyManager mTelephonyManager;
+    private WifiManager mWifiManager;
+    private CameraManager mCameraManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Instrumentation instrumentation = getInstrumentation();
+        mContext = instrumentation.getTargetContext();
+        mPackageManager = mContext.getPackageManager();
+        mAvailableFeatures = new HashSet<String>();
+        if (mPackageManager.getSystemAvailableFeatures() != null) {
+            for (FeatureInfo feature : mPackageManager.getSystemAvailableFeatures()) {
+                mAvailableFeatures.add(feature.name);
+            }
+        }
+        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+        mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
+    }
+
+    /**
+     * Check for features improperly prefixed with "android." that are not defined in
+     * {@link PackageManager}.
+     */
+    public void testFeatureNamespaces() throws IllegalArgumentException, IllegalAccessException {
+        Set<String> officialFeatures = getFeatureConstantsNames("FEATURE_");
+        assertFalse(officialFeatures.isEmpty());
+
+        Set<String> notOfficialFeatures = new HashSet<String>(mAvailableFeatures);
+        notOfficialFeatures.removeAll(officialFeatures);
+
+        for (String featureName : notOfficialFeatures) {
+            if (featureName != null) {
+                assertFalse("Use a different namespace than 'android' for " + featureName,
+                        featureName.startsWith("android"));
+            }
+        }
+    }
+
+    public void testBluetoothFeature() {
+        if (BluetoothAdapter.getDefaultAdapter() != null) {
+            assertAvailable(PackageManager.FEATURE_BLUETOOTH);
+        } else {
+            assertNotAvailable(PackageManager.FEATURE_BLUETOOTH);
+        }
+    }
+
+    public void testCameraFeatures() throws Exception {
+        int numCameras = Camera.getNumberOfCameras();
+        if (numCameras == 0) {
+            assertNotAvailable(PackageManager.FEATURE_CAMERA);
+            assertNotAvailable(PackageManager.FEATURE_CAMERA_AUTOFOCUS);
+            assertNotAvailable(PackageManager.FEATURE_CAMERA_FLASH);
+            assertNotAvailable(PackageManager.FEATURE_CAMERA_FRONT);
+            assertNotAvailable(PackageManager.FEATURE_CAMERA_ANY);
+            assertNotAvailable(PackageManager.FEATURE_CAMERA_LEVEL_FULL);
+            assertNotAvailable(PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR);
+            assertNotAvailable(PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING);
+            assertNotAvailable(PackageManager.FEATURE_CAMERA_CAPABILITY_RAW);
+
+            assertFalse("Devices supporting external cameras must have a representative camera " +
+                    "connected for testing",
+                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
+        } else {
+            assertAvailable(PackageManager.FEATURE_CAMERA_ANY);
+            checkFrontCamera();
+            checkRearCamera();
+            checkCamera2Features();
+        }
+    }
+
+    private void checkCamera2Features() throws Exception {
+        String[] cameraIds = mCameraManager.getCameraIdList();
+        boolean fullCamera = false;
+        boolean manualSensor = false;
+        boolean manualPostProcessing = false;
+        boolean raw = false;
+        CameraCharacteristics[] cameraChars = new CameraCharacteristics[cameraIds.length];
+        for (String cameraId : cameraIds) {
+            CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(cameraId);
+            Integer hwLevel = chars.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
+            int[] capabilities = chars.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+            if (hwLevel == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL) {
+                fullCamera = true;
+            }
+            for (int capability : capabilities) {
+                switch (capability) {
+                    case CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
+                        manualSensor = true;
+                        break;
+                    case CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING:
+                        manualPostProcessing = true;
+                        break;
+                    case CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW:
+                        raw = true;
+                        break;
+                    default:
+                        // Capabilities don't have a matching system feature
+                        break;
+                }
+            }
+        }
+        assertFeature(fullCamera, PackageManager.FEATURE_CAMERA_LEVEL_FULL);
+        assertFeature(manualSensor, PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR);
+        assertFeature(manualPostProcessing,
+                PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING);
+        assertFeature(raw, PackageManager.FEATURE_CAMERA_CAPABILITY_RAW);
+    }
+
+    private void checkFrontCamera() {
+        CameraInfo info = new CameraInfo();
+        int numCameras = Camera.getNumberOfCameras();
+        int frontCameraId = -1;
+        for (int i = 0; i < numCameras; i++) {
+            Camera.getCameraInfo(i, info);
+            if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
+                frontCameraId = i;
+            }
+        }
+
+        if (frontCameraId > -1) {
+            assertTrue("Device has front-facing camera but does not report either " +
+                    "the FEATURE_CAMERA_FRONT or FEATURE_CAMERA_EXTERNAL feature",
+                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT) ||
+                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
+        } else {
+            assertFalse("Device does not have front-facing camera but reports either " +
+                    "the FEATURE_CAMERA_FRONT or FEATURE_CAMERA_EXTERNAL feature",
+                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT) ||
+                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
+        }
+    }
+
+    private void checkRearCamera() {
+        Camera camera = null;
+        try {
+            camera = Camera.open();
+            if (camera != null) {
+                assertAvailable(PackageManager.FEATURE_CAMERA);
+
+                Camera.Parameters params = camera.getParameters();
+                if (params.getSupportedFocusModes().contains(Parameters.FOCUS_MODE_AUTO)) {
+                    assertAvailable(PackageManager.FEATURE_CAMERA_AUTOFOCUS);
+                } else {
+                    assertNotAvailable(PackageManager.FEATURE_CAMERA_AUTOFOCUS);
+                }
+
+                if (params.getFlashMode() != null) {
+                    assertAvailable(PackageManager.FEATURE_CAMERA_FLASH);
+                } else {
+                    assertNotAvailable(PackageManager.FEATURE_CAMERA_FLASH);
+                }
+            } else {
+                assertNotAvailable(PackageManager.FEATURE_CAMERA);
+                assertNotAvailable(PackageManager.FEATURE_CAMERA_AUTOFOCUS);
+                assertNotAvailable(PackageManager.FEATURE_CAMERA_FLASH);
+            }
+        } finally {
+            if (camera != null) {
+                camera.release();
+            }
+        }
+    }
+
+    public void testLiveWallpaperFeature() {
+        try {
+            Intent intent = new Intent(WallpaperManager.ACTION_LIVE_WALLPAPER_CHOOSER);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+            assertAvailable(PackageManager.FEATURE_LIVE_WALLPAPER);
+        } catch (ActivityNotFoundException e) {
+            assertNotAvailable(PackageManager.FEATURE_LIVE_WALLPAPER);
+        }
+    }
+
+    public void testLocationFeatures() {
+        if (mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
+            assertAvailable(PackageManager.FEATURE_LOCATION);
+            assertAvailable(PackageManager.FEATURE_LOCATION_GPS);
+        } else {
+            assertNotAvailable(PackageManager.FEATURE_LOCATION_GPS);
+        }
+
+        if (mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
+            assertAvailable(PackageManager.FEATURE_LOCATION);
+            assertAvailable(PackageManager.FEATURE_LOCATION_NETWORK);
+        } else {
+            assertNotAvailable(PackageManager.FEATURE_LOCATION_NETWORK);
+        }
+    }
+
+    public void testNfcFeatures() {
+        if (NfcAdapter.getDefaultAdapter(mContext) != null) {
+            assertAvailable(PackageManager.FEATURE_NFC);
+            assertAvailable(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
+        } else {
+            assertNotAvailable(PackageManager.FEATURE_NFC);
+        }
+    }
+
+    public void testScreenFeatures() {
+        assertTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
+                || mPackageManager.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT));
+    }
+
+    /**
+     * Check that the sensor features reported by the PackageManager correspond to the sensors
+     * returned by {@link SensorManager#getSensorList(int)}.
+     */
+    public void testSensorFeatures() throws Exception {
+        Set<String> featuresLeft = getFeatureConstantsNames("FEATURE_SENSOR_");
+
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_ACCELEROMETER,
+                Sensor.TYPE_ACCELEROMETER);
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_BAROMETER,
+                Sensor.TYPE_PRESSURE);
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_COMPASS,
+                Sensor.TYPE_MAGNETIC_FIELD);
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_GYROSCOPE,
+                Sensor.TYPE_GYROSCOPE);
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_LIGHT,
+                Sensor.TYPE_LIGHT);
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_PROXIMITY,
+                Sensor.TYPE_PROXIMITY);
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_STEP_COUNTER,
+                Sensor.TYPE_STEP_COUNTER);
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_STEP_DETECTOR,
+                Sensor.TYPE_STEP_DETECTOR);
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_AMBIENT_TEMPERATURE,
+                Sensor.TYPE_AMBIENT_TEMPERATURE);
+        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_RELATIVE_HUMIDITY,
+                Sensor.TYPE_RELATIVE_HUMIDITY);
+
+
+        /*
+         * We have three cases to test for :
+         * Case 1:  Device does not have an HRM
+         * FEATURE_SENSOR_HEART_RATE               false
+         * FEATURE_SENSOR_HEART_RATE_ECG           false
+         * assertFeatureForSensor(TYPE_HEART_RATE) false
+         *
+         * Case 2:  Device has a PPG HRM
+         * FEATURE_SENSOR_HEART_RATE               true
+         * FEATURE_SENSOR_HEART_RATE_ECG           false
+         * assertFeatureForSensor(TYPE_HEART_RATE) true
+         *
+         * Case 3:  Device has an ECG HRM
+         * FEATURE_SENSOR_HEART_RATE               false
+         * FEATURE_SENSOR_HEART_RATE_ECG           true
+         * assertFeatureForSensor(TYPE_HEART_RATE) true
+         */
+
+        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HEART_RATE_ECG)) {
+                /* Case 3 for FEATURE_SENSOR_HEART_RATE_ECG true case */
+                assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE_ECG,
+                        Sensor.TYPE_HEART_RATE);
+
+                /* Remove HEART_RATE from featuresLeft, no way to test that one */
+                assertTrue("Features left " + featuresLeft + " to check did not include "
+                        + PackageManager.FEATURE_SENSOR_HEART_RATE,
+                        featuresLeft.remove(PackageManager.FEATURE_SENSOR_HEART_RATE));
+        } else if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HEART_RATE)) {
+                /* Case 1 & 2 for FEATURE_SENSOR_HEART_RATE_ECG false case */
+                assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE_ECG,
+                        Sensor.TYPE_HEART_RATE);
+
+                /* Case 1 & 3 for FEATURE_SENSOR_HEART_RATE false case */
+                assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE,
+                        Sensor.TYPE_HEART_RATE);
+        } else {
+                /* Case 2 for FEATURE_SENSOR_HEART_RATE true case */
+                assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE,
+                        Sensor.TYPE_HEART_RATE);
+
+                /* Remove HEART_RATE_ECG from featuresLeft, no way to test that one */
+                assertTrue("Features left " + featuresLeft + " to check did not include "
+                        + PackageManager.FEATURE_SENSOR_HEART_RATE_ECG,
+                        featuresLeft.remove(PackageManager.FEATURE_SENSOR_HEART_RATE_ECG));
+        }
+
+        assertTrue("Assertions need to be added to this test for " + featuresLeft,
+                featuresLeft.isEmpty());
+    }
+
+    /** Get a list of feature constants in PackageManager matching a prefix. */
+    private static Set<String> getFeatureConstantsNames(String prefix)
+            throws IllegalArgumentException, IllegalAccessException {
+        Set<String> features = new HashSet<String>();
+        Field[] fields = PackageManager.class.getFields();
+        for (Field field : fields) {
+            if (field.getName().startsWith(prefix)) {
+                String feature = (String) field.get(null);
+                features.add(feature);
+            }
+        }
+        return features;
+    }
+
+    public void testSipFeatures() {
+        if (SipManager.newInstance(mContext) != null) {
+            assertAvailable(PackageManager.FEATURE_SIP);
+        } else {
+            assertNotAvailable(PackageManager.FEATURE_SIP);
+            assertNotAvailable(PackageManager.FEATURE_SIP_VOIP);
+        }
+
+        if (SipManager.isApiSupported(mContext)) {
+            assertAvailable(PackageManager.FEATURE_SIP);
+        } else {
+            assertNotAvailable(PackageManager.FEATURE_SIP);
+            assertNotAvailable(PackageManager.FEATURE_SIP_VOIP);
+        }
+
+        if (SipManager.isVoipSupported(mContext)) {
+            assertAvailable(PackageManager.FEATURE_SIP);
+            assertAvailable(PackageManager.FEATURE_SIP_VOIP);
+        } else {
+            assertNotAvailable(PackageManager.FEATURE_SIP_VOIP);
+        }
+    }
+
+    /**
+     * Check that if the PackageManager declares a sensor feature that the device has at least
+     * one sensor that matches that feature. Also check that if a PackageManager does not declare
+     * a sensor that the device also does not have such a sensor.
+     *
+     * @param featuresLeft to check in order to make sure the test covers all sensor features
+     * @param expectedFeature that the PackageManager may report
+     * @param expectedSensorType that that {@link SensorManager#getSensorList(int)} may have
+     */
+    private void assertFeatureForSensor(Set<String> featuresLeft, String expectedFeature,
+            int expectedSensorType) {
+        assertTrue("Features left " + featuresLeft + " to check did not include "
+                + expectedFeature, featuresLeft.remove(expectedFeature));
+
+        boolean hasSensorFeature = mPackageManager.hasSystemFeature(expectedFeature);
+
+        List<Sensor> sensors = mSensorManager.getSensorList(expectedSensorType);
+        List<String> sensorNames = new ArrayList<String>(sensors.size());
+        for (Sensor sensor : sensors) {
+            sensorNames.add(sensor.getName());
+        }
+        boolean hasSensorType = !sensors.isEmpty();
+
+        String message = "PackageManager#hasSystemFeature(" + expectedFeature + ") returns "
+                + hasSensorFeature
+                + " but SensorManager#getSensorList(" + expectedSensorType + ") shows sensors "
+                + sensorNames;
+
+        assertEquals(message, hasSensorFeature, hasSensorType);
+    }
+
+    /**
+     * Check that the {@link TelephonyManager#getPhoneType()} matches the reported features.
+     */
+    public void testTelephonyFeatures() {
+        int phoneType = mTelephonyManager.getPhoneType();
+        switch (phoneType) {
+            case TelephonyManager.PHONE_TYPE_GSM:
+                assertAvailable(PackageManager.FEATURE_TELEPHONY);
+                assertAvailable(PackageManager.FEATURE_TELEPHONY_GSM);
+                break;
+
+            case TelephonyManager.PHONE_TYPE_CDMA:
+                assertAvailable(PackageManager.FEATURE_TELEPHONY);
+                assertAvailable(PackageManager.FEATURE_TELEPHONY_CDMA);
+                break;
+
+            case TelephonyManager.PHONE_TYPE_NONE:
+                assertNotAvailable(PackageManager.FEATURE_TELEPHONY);
+                assertNotAvailable(PackageManager.FEATURE_TELEPHONY_CDMA);
+                assertNotAvailable(PackageManager.FEATURE_TELEPHONY_GSM);
+                break;
+
+            default:
+                throw new IllegalArgumentException("Did you add a new phone type? " + phoneType);
+        }
+    }
+
+    public void testTouchScreenFeatures() {
+        ConfigurationInfo configInfo = mActivityManager.getDeviceConfigurationInfo();
+        if (configInfo.reqTouchScreen != Configuration.TOUCHSCREEN_NOTOUCH) {
+            assertAvailable(PackageManager.FEATURE_TOUCHSCREEN);
+            assertAvailable(PackageManager.FEATURE_FAKETOUCH);
+        } else {
+            assertNotAvailable(PackageManager.FEATURE_TOUCHSCREEN);
+        }
+
+        // TODO: Add tests for the other touchscreen features.
+    }
+
+    public void testUsbAccessory() {
+        assertAvailable(PackageManager.FEATURE_USB_ACCESSORY);
+    }
+
+    public void testWifiFeature() throws Exception {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+            // no WiFi, skip the test
+            return;
+        }
+        boolean enabled = mWifiManager.isWifiEnabled();
+        try {
+            // WifiManager is hard-coded to return true,
+            // the case without WiFi is already handled,
+            // so this case MUST have WiFi.
+            if (mWifiManager.setWifiEnabled(true)) {
+                assertAvailable(PackageManager.FEATURE_WIFI);
+            }
+        } finally {
+            if (!enabled) {
+                mWifiManager.setWifiEnabled(false);
+            }
+        }
+    }
+
+    private void assertAvailable(String feature) {
+        assertTrue("PackageManager#hasSystemFeature should return true for " + feature,
+                mPackageManager.hasSystemFeature(feature));
+        assertTrue("PackageManager#getSystemAvailableFeatures should have " + feature,
+                mAvailableFeatures.contains(feature));
+    }
+
+    private void assertNotAvailable(String feature) {
+        assertFalse("PackageManager#hasSystemFeature should NOT return true for " + feature,
+                mPackageManager.hasSystemFeature(feature));
+        assertFalse("PackageManager#getSystemAvailableFeatures should NOT have " + feature,
+                mAvailableFeatures.contains(feature));
+    }
+
+    private void assertFeature(boolean exist, String feature) {
+        if (exist) {
+            assertAvailable(feature);
+        } else {
+            assertNotAvailable(feature);
+        }
+    }
+}
diff --git a/tests/app/src/android/app/cts/TabActivityTest.java b/tests/app/src/android/app/cts/TabActivityTest.java
new file mode 100644
index 0000000..77a17e8
--- /dev/null
+++ b/tests/app/src/android/app/cts/TabActivityTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.TabActivity;
+import android.app.stubs.MockTabActivity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.test.InstrumentationTestCase;
+import android.test.UiThreadTest;
+import android.widget.TabHost;
+
+public class TabActivityTest extends InstrumentationTestCase {
+    private Instrumentation mInstrumentation;
+    private MockTabActivity mActivity;
+    private Activity mChildActivity;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = super.getInstrumentation();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mActivity != null) {
+            if (!mActivity.isFinishing()) {
+                mActivity.finish();
+            } else if (mChildActivity != null) {
+                if (!mChildActivity.isFinishing()) {
+                    mChildActivity.finish();
+                }
+            }
+        }
+        super.tearDown();
+    }
+
+    public void testTabActivity() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                // Test constructor
+                new TabActivity();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        final String packageName = "android.app.stubs";
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClassName(packageName, MockTabActivity.class.getName());
+        mActivity = (MockTabActivity) mInstrumentation.startActivitySync(intent);
+        // Test onPostCreate, onContentChanged. These two methods are invoked in starting
+        // activity. Default values of isOnContentChangedCalled, isOnPostCreateCalled are false.
+        assertTrue(mActivity.isOnContentChangedCalled);
+        assertTrue(mActivity.isOnPostCreateCalled);
+
+        // Can't get default value.
+        final int defaultIndex = 1;
+        mActivity.setDefaultTab(defaultIndex);
+        final String defaultTab = "DefaultTab";
+        mActivity.setDefaultTab(defaultTab);
+        // Test getTabHost, getTabWidget
+        final TabHost tabHost = mActivity.getTabHost();
+        assertNotNull(tabHost);
+        assertNotNull(tabHost.getTabWidget());
+    }
+
+    @UiThreadTest
+    public void testChildTitleCallback() throws Exception {
+        final Context context = mInstrumentation.getTargetContext();
+        final Intent intent = new Intent(context, MockTabActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        final MockTabActivity father = new MockTabActivity();
+        final ComponentName componentName = new ComponentName(context, MockTabActivity.class);
+        final ActivityInfo info = context.getPackageManager().getActivityInfo(componentName, 0);
+        mChildActivity = mInstrumentation.newActivity(MockTabActivity.class, mInstrumentation
+                .getTargetContext(), null, null, intent, info, MockTabActivity.class.getName(),
+                father, null, null);
+
+        assertNotNull(mChildActivity);
+        final String newTitle = "New Title";
+        mChildActivity.setTitle(newTitle);
+        assertTrue(father.isOnChildTitleChangedCalled);
+    }
+}
diff --git a/tests/app/src/android/app/cts/TestDialog.java b/tests/app/src/android/app/cts/TestDialog.java
deleted file mode 100644
index 7effc79..0000000
--- a/tests/app/src/android/app/cts/TestDialog.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.cts;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.Window;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.WindowManager.LayoutParams;
-
-public class TestDialog extends Dialog {
-    private static final int OPTIONS_MENU_ITEM_0 = Menu.FIRST;
-    private static final int OPTIONS_MENU_ITEM_1 = Menu.FIRST + 1;
-    private static final int OPTIONS_MENU_ITEM_2 = Menu.FIRST + 2;
-    private static final int OPTIONS_MENU_ITEM_3 = Menu.FIRST + 3;
-    private static final int OPTIONS_MENU_ITEM_4 = Menu.FIRST + 4;
-    private static final int OPTIONS_MENU_ITEM_5 = Menu.FIRST + 5;
-    private static final int OPTIONS_MENU_ITEM_6 = Menu.FIRST + 6;
-    private static final int CONTEXT_MENU_ITEM_0 = Menu.FIRST + 7;
-    private static final int CONTEXT_MENU_ITEM_1 = Menu.FIRST + 8;
-    private static final int CONTEXT_MENU_ITEM_2 = Menu.FIRST + 9;
-    public boolean isOnStartCalled;
-    public boolean isOnStopCalled;
-    public boolean isOnCreateCalled;
-    public boolean isRequestWindowFeature;
-    public boolean isOnContentChangedCalled;
-    public boolean isOnWindowFocusChangedCalled;
-    public boolean isOnTouchEventCalled;
-    public boolean isOnTrackballEventCalled;
-    public boolean isOnKeyDownCalled;
-    public boolean isOnKeyUpCalled;
-    public boolean isOnKeyMultipleCalled;
-    public boolean isOnSaveInstanceStateCalled;
-    public static boolean isOnRestoreInstanceStateCalled;
-    public boolean isOnWindowAttributesChangedCalled;
-    public boolean isOnCreatePanelMenuCalled;
-    public boolean isOnCreatePanelViewCalled;
-    public boolean isOnPreparePanelCalled;
-    public boolean isOnMenuOpenedCalled;
-    public boolean isOnMenuItemSelectedCalled;
-    public boolean isOnPanelClosedCalled;
-    public boolean isOnCreateOptionsMenuCalled;
-    public boolean isOnPrepareOptionsMenuCalled;
-    public boolean isOnOptionsItemSelectedCalled;
-    public boolean isOnOptionsMenuClosedCalled;
-    public boolean isOnContextItemSelectedCalled;
-    public boolean isOnContextMenuClosedCalled;
-    public boolean isOnCreateContextMenuCalled;
-    public boolean isOnSearchRequestedCalled;
-    public boolean onKeyDownReturn;
-    public boolean onKeyMultipleReturn;
-    public boolean dispatchTouchEventResult;
-    public boolean dispatchKeyEventResult;
-    public int keyDownCode = -1;
-    public Window window;
-    public Bundle saveInstanceState;
-    public Bundle savedInstanceState;
-    public KeyEvent keyEvent;
-    public MotionEvent touchEvent;
-    public MotionEvent trackballEvent;
-    public MotionEvent onTrackballEvent;
-    public MotionEvent onTouchEvent;
-    public KeyEvent keyMultipleEvent;
-
-    public TestDialog(Context context) {
-        super(context);
-    }
-
-    public TestDialog(Context context, int theme) {
-        super(context, theme);
-    }
-
-    public TestDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
-        super(context, cancelable, cancelListener);
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-        isOnStartCalled = true;
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        isOnStopCalled = true;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        isRequestWindowFeature = requestWindowFeature(Window.FEATURE_LEFT_ICON);
-        super.onCreate(savedInstanceState);
-        isOnCreateCalled = true;
-    }
-
-    @Override
-    public void onContentChanged() {
-        super.onContentChanged();
-
-        isOnContentChangedCalled = true;
-    }
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus) {
-        super.onWindowFocusChanged(hasFocus);
-
-        isOnWindowFocusChangedCalled = true;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        isOnTouchEventCalled = true;
-        onTouchEvent = event;
-        return super.onTouchEvent(event);
-    }
-
-    @Override
-    public boolean onTrackballEvent(MotionEvent event) {
-        isOnTrackballEventCalled = true;
-        onTrackballEvent = event;
-        return super.onTrackballEvent(event);
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        isOnKeyDownCalled = true;
-        keyDownCode = keyCode;
-        onKeyDownReturn = super.onKeyDown(keyCode, event);
-
-        return onKeyDownReturn;
-    }
-
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        isOnKeyUpCalled = true;
-
-        return super.onKeyUp(keyCode, event);
-    }
-
-    @Override
-    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
-        isOnKeyMultipleCalled = true;
-        onKeyMultipleReturn = super.onKeyMultiple(keyCode, repeatCount, event);
-        keyMultipleEvent = event;
-        return onKeyMultipleReturn;
-    }
-
-    @Override
-    public Bundle onSaveInstanceState() {
-        isOnSaveInstanceStateCalled = true;
-        saveInstanceState = super.onSaveInstanceState();
-        return saveInstanceState;
-    }
-
-    @Override
-    public void onRestoreInstanceState(Bundle savedInstanceState) {
-        isOnRestoreInstanceStateCalled = true;
-        this.savedInstanceState = savedInstanceState;
-
-        super.onRestoreInstanceState(savedInstanceState);
-    }
-
-    @Override
-    public void onWindowAttributesChanged(LayoutParams params) {
-        isOnWindowAttributesChangedCalled = true;
-        super.onWindowAttributesChanged(params);
-    }
-
-    @Override
-    public boolean onCreatePanelMenu(int featureId, Menu menu) {
-        isOnCreatePanelMenuCalled = true;
-        return super.onCreatePanelMenu(featureId, menu);
-    }
-
-    @Override
-    public View onCreatePanelView(int featureId) {
-        isOnCreatePanelViewCalled = true;
-        return super.onCreatePanelView(featureId);
-    }
-
-    @Override
-    public boolean onPreparePanel(int featureId, View view, Menu menu) {
-        isOnPreparePanelCalled = true;
-        return super.onPreparePanel(featureId, view, menu);
-    }
-
-    @Override
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {
-        isOnMenuItemSelectedCalled = true;
-        return super.onMenuItemSelected(featureId, item);
-    }
-
-    @Override
-    public boolean onMenuOpened(int featureId, Menu menu) {
-        isOnMenuOpenedCalled = true;
-        return super.onMenuOpened(featureId, menu);
-    }
-
-    @Override
-    public void onPanelClosed(int featureId, Menu menu) {
-        isOnPanelClosedCalled = true;
-        super.onPanelClosed(featureId, menu);
-    }
-
-    @Override
-    public boolean onPrepareOptionsMenu(Menu menu) {
-        isOnPrepareOptionsMenuCalled = true;
-        return super.onPrepareOptionsMenu(menu);
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        super.onCreateOptionsMenu(menu);
-        menu.add(0, OPTIONS_MENU_ITEM_0, 0, "OptionsMenuItem0");
-        menu.add(0, OPTIONS_MENU_ITEM_1, 0, "OptionsMenuItem1");
-        menu.add(0, OPTIONS_MENU_ITEM_2, 0, "OptionsMenuItem2");
-        menu.add(0, OPTIONS_MENU_ITEM_3, 0, "OptionsMenuItem3");
-        menu.add(0, OPTIONS_MENU_ITEM_4, 0, "OptionsMenuItem4");
-        menu.add(0, OPTIONS_MENU_ITEM_5, 0, "OptionsMenuItem5");
-        menu.add(0, OPTIONS_MENU_ITEM_6, 0, "OptionsMenuItem6");
-        isOnCreateOptionsMenuCalled = true;
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        isOnOptionsItemSelectedCalled = true;
-        switch (item.getItemId()) {
-            case OPTIONS_MENU_ITEM_0:
-            case OPTIONS_MENU_ITEM_1:
-            case OPTIONS_MENU_ITEM_2:
-            case OPTIONS_MENU_ITEM_3:
-            case OPTIONS_MENU_ITEM_4:
-            case OPTIONS_MENU_ITEM_5:
-            case OPTIONS_MENU_ITEM_6:
-                return true;
-            default:
-                return super.onOptionsItemSelected(item);
-        }
-    }
-
-    @Override
-    public void onOptionsMenuClosed(Menu menu) {
-        isOnOptionsMenuClosedCalled = true;
-        super.onOptionsMenuClosed(menu);
-    }
-
-    @Override
-    public boolean onContextItemSelected(MenuItem item) {
-        isOnContextItemSelectedCalled = true;
-        switch (item.getItemId()) {
-            case CONTEXT_MENU_ITEM_0:
-            case CONTEXT_MENU_ITEM_1:
-            case CONTEXT_MENU_ITEM_2:
-                return true;
-            default:
-                return super.onContextItemSelected(item);
-        }
-    }
-
-    @Override
-    public void onContextMenuClosed(Menu menu) {
-        isOnContextMenuClosedCalled = true;
-        super.onContextMenuClosed(menu);
-    }
-
-    @Override
-    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
-        menu.add(0, CONTEXT_MENU_ITEM_0, 0, "ContextMenuItem0");
-        menu.add(0, CONTEXT_MENU_ITEM_1, 0, "ContextMenuItem1");
-        menu.add(0, CONTEXT_MENU_ITEM_2, 0, "ContextMenuItem2");
-        isOnCreateContextMenuCalled = true;
-    }
-
-    @Override
-    public boolean onSearchRequested() {
-        isOnSearchRequestedCalled = true;
-        return super.onSearchRequested();
-    }
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        keyEvent = event;
-        dispatchKeyEventResult = super.dispatchKeyEvent(event);
-        return dispatchKeyEventResult;
-    }
-
-    @Override
-    public boolean dispatchTrackballEvent(MotionEvent ev) {
-        trackballEvent = ev;
-        return super.dispatchTrackballEvent(ev);
-    }
-
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent ev) {
-        touchEvent = ev;
-        dispatchTouchEventResult = super.dispatchTouchEvent(ev);
-        return dispatchTouchEventResult;
-    }
-}
diff --git a/tests/app/src/android/app/cts/TestedActivity.java b/tests/app/src/android/app/cts/TestedActivity.java
deleted file mode 100644
index b6565bf..0000000
--- a/tests/app/src/android/app/cts/TestedActivity.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.Looper;
-import android.os.MessageQueue;
-import android.util.Log;
-
-public class TestedActivity extends Activity {
-    private static final String TAG = "TestedActivity" ;
-    public TestedActivity() {
-    }
-
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-    }
-
-    protected void onRestoreInstanceState(Bundle state) {
-        super.onRestoreInstanceState(state);
-    }
-
-    protected void onResume() {
-        super.onResume();
-        Looper.myLooper();
-        Looper.myQueue().addIdleHandler(new Idler());
-    }
-
-    protected void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-    }
-
-    protected void onStop() {
-        super.onStop();
-    }
-
-    private class Idler implements MessageQueue.IdleHandler {
-        public final boolean queueIdle() {
-            Log.i(TAG, "idle");
-            setResult(RESULT_OK);
-            finish();
-            return false;
-        }
-    }
-}
diff --git a/tests/app/src/android/app/cts/TestedScreen.java b/tests/app/src/android/app/cts/TestedScreen.java
deleted file mode 100644
index 052fb34..0000000
--- a/tests/app/src/android/app/cts/TestedScreen.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.MessageQueue;
-import android.os.SystemClock;
-import android.util.Log;
-
-public class TestedScreen extends Activity {
-    public static final String WAIT_BEFORE_FINISH = "TestedScreen.WAIT_BEFORE_FINISH";
-    public static final String DELIVER_RESULT = "TestedScreen.DELIVER_RESULT";
-    public static final String CLEAR_TASK = "TestedScreen.CLEAR_TASK";
-    private static final String TAG = "TestedScreen" ;
-    public TestedScreen() {
-    }
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        if (LaunchpadActivity.FORWARD_RESULT.equals(getIntent().getAction())) {
-            final Intent intent = new Intent(getIntent());
-            intent.setAction(DELIVER_RESULT);
-            intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
-            startActivity(intent);
-            finish();
-        } else if (DELIVER_RESULT.equals(getIntent().getAction())) {
-            setResult(RESULT_OK, new Intent().setAction(LaunchpadActivity.RETURNED_RESULT));
-            finish();
-        } else if (CLEAR_TASK.equals(getIntent().getAction())) {
-            if (!getIntent().getBooleanExtra(ClearTop.WAIT_CLEAR_TASK, false)) {
-                launchClearTask();
-            }
-        }
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Bundle state) {
-        super.onRestoreInstanceState(state);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        if (CLEAR_TASK.equals(getIntent().getAction())) {
-            if (getIntent().getBooleanExtra(ClearTop.WAIT_CLEAR_TASK, false)) {
-                Looper.myLooper();
-                Looper.myQueue().addIdleHandler(new Idler());
-            }
-        } else {
-            Looper.myLooper();
-            Looper.myQueue().addIdleHandler(new Idler());
-        }
-    }
-
-    @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-    }
-
-    private void launchClearTask() {
-        final Intent intent = new Intent(getIntent()).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
-                .setClass(this, ClearTop.class);
-        startActivity(intent);
-    }
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            if (CLEAR_TASK.equals(getIntent().getAction())) {
-                launchClearTask();
-            } else {
-                setResult(RESULT_OK);
-                finish();
-            }
-        }
-    };
-
-    private class Idler implements MessageQueue.IdleHandler {
-        public final boolean queueIdle() {
-            Log.i(TAG, "idle");
-            if (WAIT_BEFORE_FINISH.equals(getIntent().getAction())) {
-                final Message m = Message.obtain();
-                mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
-            } else if (CLEAR_TASK.equals(getIntent().getAction())) {
-                final Message m = Message.obtain();
-                mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
-            } else {
-                setResult(RESULT_OK);
-                finish();
-            }
-            return false;
-        }
-    }
-}
diff --git a/tests/app/src/android/app/cts/TimePickerDialogTest.java b/tests/app/src/android/app/cts/TimePickerDialogTest.java
new file mode 100644
index 0000000..3da25ab
--- /dev/null
+++ b/tests/app/src/android/app/cts/TimePickerDialogTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.TimePickerDialog;
+import android.app.TimePickerDialog.OnTimeSetListener;
+import android.app.stubs.DialogStubActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.widget.TimePicker;
+
+import android.app.stubs.R;
+
+/**
+ * Test {@link TimePickerDialog}.
+ */
+public class TimePickerDialogTest extends ActivityInstrumentationTestCase2<DialogStubActivity> {
+    private static final String HOUR = "hour";
+    private static final String MINUTE = "minute";
+    private static final String IS_24_HOUR = "is24hour";
+
+    private static final int TARGET_HOUR = 15;
+    private static final int TARGET_MINUTE = 9;
+
+    private int mCallbackHour;
+    private int mCallbackMinute;
+
+    private OnTimeSetListener mOnTimeSetListener;
+
+    private Context mContext;
+    private DialogStubActivity mActivity;
+
+    public TimePickerDialogTest() {
+        super("android.app.stubs", DialogStubActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mContext = getInstrumentation().getContext();
+        mOnTimeSetListener = new OnTimeSetListener(){
+            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
+                mCallbackHour = hourOfDay;
+                mCallbackMinute = minute;
+            }
+        };
+    }
+
+    @UiThreadTest
+    public void testSaveInstanceState() {
+        TimePickerDialog tD = new TimePickerDialog(
+            mContext, mOnTimeSetListener, TARGET_HOUR, TARGET_MINUTE, true);
+
+        Bundle b = tD.onSaveInstanceState();
+
+        assertEquals(TARGET_HOUR, b.getInt(HOUR));
+        assertEquals(TARGET_MINUTE, b.getInt(MINUTE));
+        assertTrue(b.getBoolean(IS_24_HOUR));
+
+        int minute = 13;
+        tD = new TimePickerDialog(
+                mContext, R.style.Theme_AlertDialog,
+                    mOnTimeSetListener, TARGET_HOUR, minute, false);
+
+        b = tD.onSaveInstanceState();
+
+        assertEquals(TARGET_HOUR, b.getInt(HOUR));
+        assertEquals(minute, b.getInt(MINUTE));
+        assertFalse(b.getBoolean(IS_24_HOUR));
+    }
+
+    @UiThreadTest
+    public void testOnClick() {
+        TimePickerDialog timePickerDialog = buildDialog();
+        timePickerDialog.onClick(null, TimePickerDialog.BUTTON_POSITIVE);
+
+        assertEquals(TARGET_HOUR, mCallbackHour);
+        assertEquals(TARGET_MINUTE, mCallbackMinute);
+    }
+
+    public void testOnTimeChanged() throws Throwable {
+        final int minute = 34;
+        startDialogActivity(DialogStubActivity.TEST_TIMEPICKERDIALOG);
+        final TimePickerDialog d = (TimePickerDialog) mActivity.getDialog();
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                d.onTimeChanged(null, TARGET_HOUR, minute);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+
+    }
+
+    @UiThreadTest
+    public void testUpdateTime() {
+        TimePickerDialog timePickerDialog = buildDialog();
+        int minute = 18;
+        timePickerDialog.updateTime(TARGET_HOUR, minute);
+
+        // here call onSaveInstanceState is to check the data put by updateTime
+        Bundle b = timePickerDialog.onSaveInstanceState();
+
+        assertEquals(TARGET_HOUR, b.getInt(HOUR));
+        assertEquals(minute, b.getInt(MINUTE));
+    }
+
+    @UiThreadTest
+    public void testOnRestoreInstanceState() {
+        int minute = 27;
+        Bundle b1 = new Bundle();
+        b1.putInt(HOUR, TARGET_HOUR);
+        b1.putInt(MINUTE, minute);
+        b1.putBoolean(IS_24_HOUR, false);
+
+        TimePickerDialog timePickerDialog = buildDialog();
+        timePickerDialog.onRestoreInstanceState(b1);
+
+        //here call onSaveInstanceState is to check the data put by onRestoreInstanceState
+        Bundle b2 = timePickerDialog.onSaveInstanceState();
+
+        assertEquals(TARGET_HOUR, b2.getInt(HOUR));
+        assertEquals(minute, b2.getInt(MINUTE));
+        assertFalse(b2.getBoolean(IS_24_HOUR));
+    }
+
+    private void startDialogActivity(int dialogNumber) {
+        mActivity = DialogStubActivity.startDialogActivity(this, dialogNumber);
+    }
+
+    private TimePickerDialog buildDialog() {
+        return new TimePickerDialog(
+                mContext, mOnTimeSetListener, TARGET_HOUR, TARGET_MINUTE, true);
+    }
+}
diff --git a/tests/app/src/android/app/cts/UiModeManagerTest.java b/tests/app/src/android/app/cts/UiModeManagerTest.java
new file mode 100644
index 0000000..71a6427
--- /dev/null
+++ b/tests/app/src/android/app/cts/UiModeManagerTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.cts;
+
+import android.app.UiModeManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+public class UiModeManagerTest extends AndroidTestCase {
+    private static final String TAG = "UiModeManagerTest";
+
+    private UiModeManager mUiModeManager;
+    private boolean mIsAuto = false;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mUiModeManager = (UiModeManager) getContext().getSystemService(Context.UI_MODE_SERVICE);
+        assertNotNull(mUiModeManager);
+        mIsAuto = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUTOMOTIVE);
+    }
+
+    public void testCarMode() throws Exception {
+        if (mIsAuto) {
+            Log.i(TAG, "testCarMode automotive");
+            doTestCarModeAutomotive();
+        } else {
+            Log.i(TAG, "testCarMode generic");
+            doTestCarModeGeneric();
+        }
+    }
+
+    private void doTestCarModeAutomotive() throws Exception {
+        assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+        assertTrue(mUiModeManager.isUiModeLocked());
+        doTestLockedUiMode();
+        assertTrue(mUiModeManager.isNightModeLocked());
+        doTestLockedNightMode();
+    }
+
+    private void doTestCarModeGeneric() throws Exception {
+        if (mUiModeManager.isUiModeLocked()) {
+            doTestLockedUiMode();
+        } else {
+            doTestUnlockedUiMode();
+        }
+        if (mUiModeManager.isNightModeLocked()) {
+            doTestLockedNightMode();
+        } else {
+            doTestUnlockedNightMode();
+        }
+    }
+
+    private void doTestLockedUiMode() throws Exception {
+        mUiModeManager.enableCarMode(0);
+        assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+        mUiModeManager.disableCarMode(0);
+        assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+    }
+
+    private void doTestUnlockedUiMode() throws Exception {
+        mUiModeManager.enableCarMode(0);
+        assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+        mUiModeManager.disableCarMode(0);
+        assertNotSame(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+    }
+
+    private void doTestLockedNightMode() throws Exception {
+        int currentMode = mUiModeManager.getNightMode();
+        if (currentMode == UiModeManager.MODE_NIGHT_YES) {
+            mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
+            assertEquals(currentMode, mUiModeManager.getNightMode());
+        } else {
+            mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_YES);
+            assertEquals(currentMode, mUiModeManager.getNightMode());
+        }
+    }
+
+    private void doTestUnlockedNightMode() throws Exception {
+        // day night mode should be settable regardless of car mode.
+        mUiModeManager.enableCarMode(0);
+        doTestAllNightModes();
+        mUiModeManager.disableCarMode(0);
+        doTestAllNightModes();
+    }
+
+    private void doTestAllNightModes() {
+        assertNightModeChange(UiModeManager.MODE_NIGHT_AUTO);
+        assertNightModeChange(UiModeManager.MODE_NIGHT_YES);
+        assertNightModeChange(UiModeManager.MODE_NIGHT_NO);
+    }
+
+    private void assertNightModeChange(int mode) {
+        mUiModeManager.setNightMode(mode);
+        assertEquals(mode, mUiModeManager.getNightMode());
+    }
+}
diff --git a/tests/tests/app/src/android/app/cts/WallpaperManagerTest.java b/tests/app/src/android/app/cts/WallpaperManagerTest.java
similarity index 100%
rename from tests/tests/app/src/android/app/cts/WallpaperManagerTest.java
rename to tests/app/src/android/app/cts/WallpaperManagerTest.java
diff --git a/tests/browser/Android.mk b/tests/browser/Android.mk
new file mode 100644
index 0000000..a85c960
--- /dev/null
+++ b/tests/browser/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner ctstestserver
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_PACKAGE_NAME := CtsBrowserTestCases
+
+LOCAL_SDK_VERSION := 16
+
+include $(BUILD_CTS_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/browser/AndroidManifest.xml b/tests/browser/AndroidManifest.xml
new file mode 100644
index 0000000..f850e28
--- /dev/null
+++ b/tests/browser/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.browser.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="android.browser.cts" />
+</manifest>
diff --git a/tests/browser/AndroidTest.xml b/tests/browser/AndroidTest.xml
new file mode 100644
index 0000000..49c93fc
--- /dev/null
+++ b/tests/browser/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Browser test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsBrowserTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.browser.cts" />
+        <option name="runtime-hint" value="4m14s" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/base.js b/tests/browser/assets/octane/base.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/base.js
rename to tests/browser/assets/octane/base.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/box2d.js b/tests/browser/assets/octane/box2d.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/box2d.js
rename to tests/browser/assets/octane/box2d.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/code-load.js b/tests/browser/assets/octane/code-load.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/code-load.js
rename to tests/browser/assets/octane/code-load.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/crypto.js b/tests/browser/assets/octane/crypto.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/crypto.js
rename to tests/browser/assets/octane/crypto.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/css/bootstrap-responsive.css b/tests/browser/assets/octane/css/bootstrap-responsive.css
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/css/bootstrap-responsive.css
rename to tests/browser/assets/octane/css/bootstrap-responsive.css
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/css/bootstrap.css b/tests/browser/assets/octane/css/bootstrap.css
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/css/bootstrap.css
rename to tests/browser/assets/octane/css/bootstrap.css
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/css/docs.css b/tests/browser/assets/octane/css/docs.css
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/css/docs.css
rename to tests/browser/assets/octane/css/docs.css
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/cts_report.html b/tests/browser/assets/octane/cts_report.html
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/cts_report.html
rename to tests/browser/assets/octane/cts_report.html
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/cts_report.js b/tests/browser/assets/octane/cts_report.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/cts_report.js
rename to tests/browser/assets/octane/cts_report.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/deltablue.js b/tests/browser/assets/octane/deltablue.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/deltablue.js
rename to tests/browser/assets/octane/deltablue.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/earley-boyer.js b/tests/browser/assets/octane/earley-boyer.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/earley-boyer.js
rename to tests/browser/assets/octane/earley-boyer.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/gbemu.js b/tests/browser/assets/octane/gbemu.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/gbemu.js
rename to tests/browser/assets/octane/gbemu.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/ico/apple-touch-icon-114-precomposed.png b/tests/browser/assets/octane/ico/apple-touch-icon-114-precomposed.png
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/ico/apple-touch-icon-114-precomposed.png
rename to tests/browser/assets/octane/ico/apple-touch-icon-114-precomposed.png
Binary files differ
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/ico/apple-touch-icon-144-precomposed.png b/tests/browser/assets/octane/ico/apple-touch-icon-144-precomposed.png
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/ico/apple-touch-icon-144-precomposed.png
rename to tests/browser/assets/octane/ico/apple-touch-icon-144-precomposed.png
Binary files differ
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/ico/apple-touch-icon-57-precomposed.png b/tests/browser/assets/octane/ico/apple-touch-icon-57-precomposed.png
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/ico/apple-touch-icon-57-precomposed.png
rename to tests/browser/assets/octane/ico/apple-touch-icon-57-precomposed.png
Binary files differ
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/ico/apple-touch-icon-72-precomposed.png b/tests/browser/assets/octane/ico/apple-touch-icon-72-precomposed.png
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/ico/apple-touch-icon-72-precomposed.png
rename to tests/browser/assets/octane/ico/apple-touch-icon-72-precomposed.png
Binary files differ
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/ico/favicon.ico b/tests/browser/assets/octane/ico/favicon.ico
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/ico/favicon.ico
rename to tests/browser/assets/octane/ico/favicon.ico
Binary files differ
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/index.html b/tests/browser/assets/octane/index.html
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/index.html
rename to tests/browser/assets/octane/index.html
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/js/bootstrap-collapse.js b/tests/browser/assets/octane/js/bootstrap-collapse.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/js/bootstrap-collapse.js
rename to tests/browser/assets/octane/js/bootstrap-collapse.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/js/bootstrap-transition.js b/tests/browser/assets/octane/js/bootstrap-transition.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/js/bootstrap-transition.js
rename to tests/browser/assets/octane/js/bootstrap-transition.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/js/jquery.js b/tests/browser/assets/octane/js/jquery.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/js/jquery.js
rename to tests/browser/assets/octane/js/jquery.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/mandreel.js b/tests/browser/assets/octane/mandreel.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/mandreel.js
rename to tests/browser/assets/octane/mandreel.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/navier-stokes.js b/tests/browser/assets/octane/navier-stokes.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/navier-stokes.js
rename to tests/browser/assets/octane/navier-stokes.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/pdfjs.js b/tests/browser/assets/octane/pdfjs.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/pdfjs.js
rename to tests/browser/assets/octane/pdfjs.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/raytrace.js b/tests/browser/assets/octane/raytrace.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/raytrace.js
rename to tests/browser/assets/octane/raytrace.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/regexp.js b/tests/browser/assets/octane/regexp.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/regexp.js
rename to tests/browser/assets/octane/regexp.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/richards.js b/tests/browser/assets/octane/richards.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/richards.js
rename to tests/browser/assets/octane/richards.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/run.js b/tests/browser/assets/octane/run.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/run.js
rename to tests/browser/assets/octane/run.js
diff --git a/suite/cts/deviceTests/browserbench/assets/octane/splay.js b/tests/browser/assets/octane/splay.js
similarity index 100%
rename from suite/cts/deviceTests/browserbench/assets/octane/splay.js
rename to tests/browser/assets/octane/splay.js
diff --git a/tests/browser/src/android/browser/cts/BrowserBenchTest.java b/tests/browser/src/android/browser/cts/BrowserBenchTest.java
new file mode 100644
index 0000000..ff1a2ab
--- /dev/null
+++ b/tests/browser/src/android/browser/cts/BrowserBenchTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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 android.browser.cts;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.cts.util.CtsAndroidTestCase;
+import android.cts.util.WatchDog;
+import android.net.Uri;
+import android.provider.Browser;
+import android.util.Log;
+import android.webkit.cts.CtsTestServer;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+import com.android.cts.util.TimeoutReq;
+
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.RequestLine;
+
+import java.net.URLDecoder;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+/**
+ * Browser benchmarking.
+ * It launches an activity with URL and wait for POST from the client.
+ */
+public class BrowserBenchTest extends CtsAndroidTestCase {
+    private static final String TAG = BrowserBenchTest.class.getSimpleName();
+    private static final boolean DEBUG = false;
+    private static final String OCTANE_START_FILE = "octane/index.html";
+    private static final String ROBOHORNET_START_FILE = "robohornet/robohornet.html";
+    private static final String HOST_COMPLETION_BROADCAST = "android.browser.cts.completion";
+    // time-out for watch-dog. POST should happen within this time.
+    private static long BROWSER_POST_TIMEOUT_IN_MS = 10 * 60 * 1000L;
+    // watch-dog will time-out first. So make it long enough.
+    private static long BROWSER_COMPLETION_TIMEOUT_IN_MS = 60 * 60 * 1000L;
+    private static final String HTTP_USER_AGENT = "User-Agent";
+    private CtsTestServer mWebServer;
+    // used for final score
+    private ResultType mTypeNonFinal = ResultType.NEUTRAL;
+    private ResultUnit mUnitNonFinal = ResultUnit.NONE;
+    // used for all other scores
+    private ResultType mTypeFinal = ResultType.NEUTRAL;
+    private ResultUnit mUnitFinal = ResultUnit.SCORE;
+    private WatchDog mWatchDog;
+    private CountDownLatch mLatch;
+    // can be changed by each test before starting
+    private volatile int mNumberRepeat;
+    /** tells how many tests have run up to now */
+    private volatile int mRunIndex;
+    /** stores results for each runs. last entry will be the final score. */
+    private LinkedHashMap<String, double[]> mResultsMap;
+    private PackageManager mPackageManager;
+    private DeviceReportLog mReport;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mReport = new DeviceReportLog();
+        mPackageManager = getInstrumentation().getContext().getPackageManager();
+        mWebServer = new CtsTestServer(getContext()) {
+            @Override
+            protected HttpResponse onPost(HttpRequest request) throws Exception {
+                // post uri will look like "cts_report.html?final=1&score=10.1&message=hello"
+                RequestLine requestLine = request.getRequestLine();
+                String uriString = URLDecoder.decode(requestLine.getUri(), "UTF-8");
+                if (DEBUG) {
+                    Log.i(TAG, "uri:" + uriString);
+                }
+                String resultRe =
+                        ".*cts_report.html\\?final=([\\d])&score=([\\d]+\\.?[\\d]*)&message=([\\w][\\w ]*)";
+                Pattern resultPattern = Pattern.compile(resultRe);
+                Matcher matchResult = resultPattern.matcher(uriString);
+                if (matchResult.find()) {
+                    int isFinal = Integer.parseInt(matchResult.group(1));
+                    double score = Double.parseDouble(matchResult.group(2));
+                    String message = matchResult.group(3);
+                    Log.i(TAG, message + ":" + score);
+                    if (!mResultsMap.containsKey(message)) {
+                        mResultsMap.put(message, new double[mNumberRepeat]);
+                    }
+                    double[] scores = mResultsMap.get(message);
+                    scores[mRunIndex] = score;
+                    if (isFinal == 1) {
+                        String userAgent = request.getFirstHeader(HTTP_USER_AGENT).getValue();
+                        mReport.addValue(HTTP_USER_AGENT + "=" + userAgent, 0,
+                                ResultType.NEUTRAL, ResultUnit.NONE);
+                        mLatch.countDown();
+                    }
+                    mWatchDog.reset();
+                }
+                return null; // default response is OK as it will be ignored by client anyway.
+            }
+        };
+        mResultsMap = new LinkedHashMap<String, double[]>();
+        mWatchDog = new WatchDog(BROWSER_POST_TIMEOUT_IN_MS);
+        mWatchDog.start();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mWatchDog.stop();
+        mWebServer.shutdown();
+        mWebServer = null;
+        mResultsMap = null;
+        mReport.submit(getInstrumentation());
+        super.tearDown();
+    }
+
+    @TimeoutReq(minutes = 60)
+    public void testOctane() throws InterruptedException {
+        if (!isBrowserSupported()) {
+            Log.i(TAG, "Skipping test for device with no supported browser");
+            return;
+        }
+        String url = mWebServer.getAssetUrl(OCTANE_START_FILE) + "?auto=1";
+        final int kRepeat = 5;
+        doTest(url, ResultType.LOWER_BETTER, ResultUnit.MS,
+                ResultType.HIGHER_BETTER, ResultUnit.SCORE, kRepeat);
+    }
+
+    private void doTest(String url, ResultType typeNonFinal, ResultUnit unitNonFinal,
+            ResultType typeFinal, ResultUnit unitFinal, int numberRepeat)
+                    throws InterruptedException {
+        mTypeNonFinal = typeNonFinal;
+        mUnitNonFinal = unitNonFinal;
+        mTypeFinal = typeFinal;
+        mUnitFinal = unitFinal;
+        mNumberRepeat = numberRepeat;
+        Uri uri = Uri.parse(url);
+        for (mRunIndex = 0; mRunIndex < numberRepeat; mRunIndex++) {
+            Log.i(TAG, mRunIndex + "-th round");
+            mLatch = new CountDownLatch(1);
+            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            // force using only one window or tab
+            intent.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName());
+            getContext().startActivity(intent);
+            boolean ok = mLatch.await(BROWSER_COMPLETION_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS);
+            assertTrue("timed-out", ok);
+        }
+        // it is somewhat awkward to handle the last one specially with Map
+        int numberEntries = mResultsMap.size();
+        int numberToProcess = 1; 
+        for (Map.Entry<String, double[]> entry : mResultsMap.entrySet()) {
+            String message = entry.getKey();
+            double[] scores = entry.getValue();
+            if (numberToProcess == numberEntries) { // final score
+                // store the whole results first
+                mReport.addValues(message, scores, mTypeFinal, mUnitFinal);
+                mReport.setSummary(message, Stat.getAverage(scores), mTypeFinal, mUnitFinal);
+            } else { // interim results
+                mReport.addValues(message, scores, mTypeNonFinal, mUnitNonFinal);
+            }
+            numberToProcess++;
+        }
+    }
+
+    /**
+     * @return true iff this device is has a working browser.
+     */
+    private boolean isBrowserSupported() {
+        return !(mPackageManager.hasSystemFeature("android.hardware.type.television")
+                 || mPackageManager.hasSystemFeature("android.software.leanback")
+                 || mPackageManager.hasSystemFeature("android.hardware.type.watch"));
+    }
+}
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
index 4cae7c4..d072975 100644
--- a/tests/camera/Android.mk
+++ b/tests/camera/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_PACKAGE_NAME := CtsCameraTestCases
 
 LOCAL_SDK_VERSION := current
diff --git a/tests/camera/AndroidTest.xml b/tests/camera/AndroidTest.xml
new file mode 100644
index 0000000..df15689
--- /dev/null
+++ b/tests/camera/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Camera test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsCameraTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.camera.cts" />
+        <option name="runtime-hint" value="12m7s" />
+    </test>
+</configuration>
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
index 44fda14..3778b95 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -425,6 +425,7 @@
         // method on the camera device or session.
 
         class ChainedCaptureCallback extends CameraCaptureSession.CaptureCallback {
+            @Override
             public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
                     TotalCaptureResult result) {
                 try {
@@ -450,6 +451,7 @@
                 }
             }
 
+            @Override
             public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
                     CaptureFailure failure) {
                 try {
@@ -466,6 +468,7 @@
         class ChainedSessionListener extends CameraCaptureSession.StateCallback {
             private final ChainedCaptureCallback mCaptureCallback = new ChainedCaptureCallback();
 
+            @Override
             public void onConfigured(CameraCaptureSession session) {
                 try {
                     CaptureRequest.Builder request =
@@ -486,6 +489,7 @@
                 }
             }
 
+            @Override
             public void onConfigureFailed(CameraCaptureSession session) {
                 try {
                     CameraDevice camera = session.getDevice();
@@ -503,6 +507,7 @@
 
             public CameraDevice cameraDevice;
 
+            @Override
             public void onOpened(CameraDevice camera) {
 
                 cameraDevice = camera;
@@ -525,6 +530,7 @@
                 }
             }
 
+            @Override
             public void onDisconnected(CameraDevice camera) {
                 try {
                     camera.close();
@@ -534,6 +540,7 @@
                 }
             }
 
+            @Override
             public void onError(CameraDevice camera, int error) {
                 try {
                     camera.close();
@@ -1508,7 +1515,6 @@
             }
         }
 
-        // Edge enhancement and noise reduction modes
         boolean supportReprocessing =
                 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING) ||
                 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
@@ -1522,6 +1528,7 @@
                         CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX);
             }
 
+            // Edge enhancement, noise reduction and aberration correction modes.
             mCollector.expectEquals("Edge mode must be present in request if " +
                             "available edge modes are present in metadata, and vice-versa.",
                     mStaticInfo.areKeysAvailable(CameraCharacteristics.
@@ -1530,12 +1537,10 @@
             if (mStaticInfo.areKeysAvailable(EDGE_MODE)) {
                 List<Integer> availableEdgeModes =
                         Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked()));
+                // Don't need check fast as fast or high quality must be both present or both not.
                 if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY)) {
                     mCollector.expectKeyValueEquals(request, EDGE_MODE,
                             CaptureRequest.EDGE_MODE_HIGH_QUALITY);
-                } else if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_FAST)) {
-                    mCollector.expectKeyValueEquals(request, EDGE_MODE,
-                            CaptureRequest.EDGE_MODE_FAST);
                 } else {
                     mCollector.expectKeyValueEquals(request, EDGE_MODE,
                             CaptureRequest.EDGE_MODE_OFF);
@@ -1551,25 +1556,86 @@
                     CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES)) {
                 List<Integer> availableNoiseReductionModes =
                         Arrays.asList(toObject(mStaticInfo.getAvailableNoiseReductionModesChecked()));
+                // Don't need check fast as fast or high quality must be both present or both not.
                 if (availableNoiseReductionModes
                         .contains(CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY)) {
                     mCollector.expectKeyValueEquals(
                             request, NOISE_REDUCTION_MODE,
                             CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
-                } else if (availableNoiseReductionModes
-                        .contains(CaptureRequest.NOISE_REDUCTION_MODE_FAST)) {
-                    mCollector.expectKeyValueEquals(
-                            request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_FAST);
                 } else {
                     mCollector.expectKeyValueEquals(
                             request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
                 }
             }
+
+            boolean supportAvailableAberrationModes = mStaticInfo.areKeysAvailable(
+                    CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES);
+            boolean supportAberrationRequestKey = mStaticInfo.areKeysAvailable(
+                    CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
+            mCollector.expectEquals("Aberration correction mode must be present in request if " +
+                    "available aberration correction reductions are present in metadata, and "
+                    + "vice-versa.", supportAvailableAberrationModes, supportAberrationRequestKey);
+            if (supportAberrationRequestKey) {
+                List<Integer> availableAberrationModes = Arrays.asList(
+                        toObject(mStaticInfo.getAvailableColorAberrationModesChecked()));
+                // Don't need check fast as fast or high quality must be both present or both not.
+                if (availableAberrationModes
+                        .contains(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY)) {
+                    mCollector.expectKeyValueEquals(
+                            request, COLOR_CORRECTION_ABERRATION_MODE,
+                            CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
+                } else {
+                    mCollector.expectKeyValueEquals(
+                            request, COLOR_CORRECTION_ABERRATION_MODE,
+                            CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
+                }
+            }
         } else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG && supportReprocessing) {
             mCollector.expectKeyValueEquals(request, EDGE_MODE,
                     CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG);
             mCollector.expectKeyValueEquals(request, NOISE_REDUCTION_MODE,
                     CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG);
+        } else if (template == CameraDevice.TEMPLATE_PREVIEW ||
+                template == CameraDevice.TEMPLATE_RECORD){
+            List<Integer> availableEdgeModes =
+                    Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked()));
+            if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_FAST)) {
+                mCollector.expectKeyValueEquals(request, EDGE_MODE,
+                        CaptureRequest.EDGE_MODE_FAST);
+            } else {
+                mCollector.expectKeyValueEquals(request, EDGE_MODE,
+                        CaptureRequest.EDGE_MODE_OFF);
+            }
+
+            if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) {
+                List<Integer> availableNoiseReductionModes =
+                        Arrays.asList(toObject(
+                                mStaticInfo.getAvailableNoiseReductionModesChecked()));
+                if (availableNoiseReductionModes
+                        .contains(CaptureRequest.NOISE_REDUCTION_MODE_FAST)) {
+                    mCollector.expectKeyValueEquals(
+                            request, NOISE_REDUCTION_MODE,
+                            CaptureRequest.NOISE_REDUCTION_MODE_FAST);
+                } else {
+                    mCollector.expectKeyValueEquals(
+                            request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
+                }
+            }
+
+            if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_ABERRATION_MODE)) {
+                List<Integer> availableAberrationModes = Arrays.asList(
+                        toObject(mStaticInfo.getAvailableColorAberrationModesChecked()));
+                if (availableAberrationModes
+                        .contains(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_FAST)) {
+                    mCollector.expectKeyValueEquals(
+                            request, COLOR_CORRECTION_ABERRATION_MODE,
+                            CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_FAST);
+                } else {
+                    mCollector.expectKeyValueEquals(
+                            request, COLOR_CORRECTION_ABERRATION_MODE,
+                            CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
+                }
+            }
         } else {
             if (mStaticInfo.areKeysAvailable(EDGE_MODE)) {
                 mCollector.expectKeyValueNotNull(request, EDGE_MODE);
@@ -1578,6 +1644,10 @@
             if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) {
                 mCollector.expectKeyValueNotNull(request, NOISE_REDUCTION_MODE);
             }
+
+            if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_ABERRATION_MODE)) {
+                mCollector.expectKeyValueNotNull(request, COLOR_CORRECTION_ABERRATION_MODE);
+            }
         }
 
         // Tone map and lens shading modes.
@@ -1681,6 +1751,7 @@
      * @param listener The {@link #CaptureCallback} camera device used to notify callbacks.
      * @param handler The handler camera device used to post callbacks.
      */
+    @Override
     protected void startCapture(CaptureRequest request, boolean repeating,
             CameraCaptureSession.CaptureCallback listener, Handler handler)
                     throws CameraAccessException {
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
index d78b3b5..85eeb0b 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -818,7 +818,8 @@
         ByteBuffer buffer = null;
         // JPEG doesn't have pixelstride and rowstride, treat it as 1D buffer.
         // Same goes for DEPTH_POINT_CLOUD
-        if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD) {
+        if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD ||
+                format == ImageFormat.RAW_PRIVATE) {
             buffer = planes[0].getBuffer();
             assertNotNull("Fail to get jpeg or depth ByteBuffer", buffer);
             data = new byte[buffer.remaining()];
@@ -898,6 +899,7 @@
                 break;
             case ImageFormat.JPEG:
             case ImageFormat.RAW_SENSOR:
+            case ImageFormat.RAW_PRIVATE:
             case ImageFormat.DEPTH16:
             case ImageFormat.DEPTH_POINT_CLOUD:
                 assertEquals("JPEG/RAW/depth Images should have one plane", 1, planes.length);
@@ -1320,6 +1322,9 @@
             case ImageFormat.DEPTH_POINT_CLOUD:
                 validateDepthPointCloudData(data, width, height, format, image.getTimestamp(), filePath);
                 break;
+            case ImageFormat.RAW_PRIVATE:
+                validateRawPrivateData(data, width, height, image.getTimestamp(), filePath);
+                break;
             default:
                 throw new UnsupportedOperationException("Unsupported format for validation: "
                         + format);
@@ -1416,6 +1421,26 @@
         return;
     }
 
+    private static void validateRawPrivateData(byte[] rawData, int width, int height,
+            long ts, String filePath) {
+        if (VERBOSE) Log.v(TAG, "Validating private raw data");
+        // Expect each RAW pixel should occupy at least one byte and no more than 2.5 bytes
+        int expectedSizeMin = width * height;
+        int expectedSizeMax = width * height * 5 / 2;
+
+        assertTrue("Opaque RAW size " + rawData.length + "out of normal bound [" +
+                expectedSizeMin + "," + expectedSizeMax + "]",
+                expectedSizeMin <= rawData.length && rawData.length <= expectedSizeMax);
+
+        if (DEBUG && filePath != null) {
+            String fileName =
+                    filePath + "/" + width + "x" + height + "_" + ts / 1e6 + ".rawPriv";
+            dumpFile(fileName, rawData);
+        }
+
+        return;
+    }
+
     private static void validateDepth16Data(byte[] depthData, int width, int height, int format,
             long ts, String filePath) {
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
index dd4e3e3..a4e1917 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -29,18 +29,20 @@
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
+import android.hardware.camera2.params.BlackLevelPattern;
 import android.hardware.camera2.params.ColorSpaceTransform;
 import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.LensShadingMap;
 import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.params.RggbChannelVector;
 import android.hardware.camera2.params.TonemapCurve;
-
+import android.media.Image;
 import android.util.Log;
 import android.util.Range;
 import android.util.Rational;
 import android.util.Size;
 
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -85,11 +87,12 @@
     private static final float FOCUS_DISTANCE_ERROR_PERCENT_APPROXIMATE = 0.10f;
     private static final int ANTI_FLICKERING_50HZ = 1;
     private static final int ANTI_FLICKERING_60HZ = 2;
-
     // 5 percent error margin for resulting crop regions
     private static final float CROP_REGION_ERROR_PERCENT_DELTA = 0.05f;
     // 1 percent error margin for centering the crop region
     private static final float CROP_REGION_ERROR_PERCENT_CENTERED = 0.01f;
+    private static final float DYNAMIC_VS_FIXED_BLK_WH_LVL_ERROR_MARGIN = 0.25f;
+    private static final float DYNAMIC_VS_OPTICAL_BLK_LVL_ERROR_MARGIN = 0.1f;
 
     // Linear tone mapping curve example.
     private static final float[] TONEMAP_CURVE_LINEAR = {0, 0, 1.0f, 1.0f};
@@ -178,6 +181,32 @@
     }
 
     /**
+     * Test dynamic black/white levels if they are supported.
+     *
+     * <p>
+     * If the dynamic black and white levels are reported, test below:
+     *   1. the dynamic black and white levels shouldn't deviate from the global value too much
+     *   for different sensitivities.
+     *   2. If the RAW_SENSOR and optical black regions are supported, capture RAW images and
+     *   calculate the optical black level values. The reported dynamic black level should be
+     *   close enough to the optical black level values.
+     * </p>
+     */
+    public void testDynamicBlackWhiteLevel() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                openDevice(id);
+                if (!mStaticInfo.isDynamicBlackLevelSupported()) {
+                    continue;
+                }
+                dynamicBlackWhiteLevelTestByCamera();
+            } finally {
+                closeDevice();
+            }
+        }
+    }
+
+    /**
      * Basic lens shading map request test.
      * <p>
      * When {@link CaptureRequest#SHADING_MODE} is set to OFF, no lens shading correction will
@@ -630,6 +659,170 @@
 
     // TODO: add 3A state machine test.
 
+    /**
+     * Per camera dynamic black and white level test.
+     */
+    private void dynamicBlackWhiteLevelTestByCamera() throws Exception {
+        SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
+        SimpleImageReaderListener imageListener = null;
+        CaptureRequest.Builder previewBuilder =
+                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+        CaptureRequest.Builder rawBuilder = null;
+        Size previewSize =
+                getMaxPreviewSize(mCamera.getId(), mCameraManager,
+                getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
+        Size rawSize = null;
+        boolean canCaptureBlackRaw =
+                mStaticInfo.isCapabilitySupported(
+                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW) &&
+                mStaticInfo.isOpticalBlackRegionSupported();
+        if (canCaptureBlackRaw) {
+            // Capture Raw16, then calculate the optical black, and use it to check with the dynamic
+            // black level.
+            rawBuilder =
+                    mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+            rawSize = mStaticInfo.getRawDimensChecked();
+            imageListener = new SimpleImageReaderListener();
+            prepareRawCaptureAndStartPreview(previewBuilder, rawBuilder, previewSize, rawSize,
+                    resultListener, imageListener);
+        } else {
+            startPreview(previewBuilder, previewSize, resultListener);
+        }
+
+        // Capture a sequence of frames with different sensitivities and validate the black/white
+        // level values
+        int[] sensitivities = getSensitivityTestValues();
+        float[][] dynamicBlackLevels = new float[sensitivities.length][];
+        int[] dynamicWhiteLevels = new int[sensitivities.length];
+        float[][] opticalBlackLevels = new float[sensitivities.length][];
+        for (int i = 0; i < sensitivities.length; i++) {
+            CaptureResult result = null;
+            if (canCaptureBlackRaw) {
+                changeExposure(rawBuilder, DEFAULT_EXP_TIME_NS, sensitivities[i]);
+                CaptureRequest rawRequest = rawBuilder.build();
+                mSession.capture(rawRequest, resultListener, mHandler);
+                result = resultListener.getCaptureResultForRequest(rawRequest,
+                        NUM_RESULTS_WAIT_TIMEOUT);
+                Image rawImage = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+
+                // Get max (area-wise) optical black region
+                Rect[] opticalBlackRegions = mStaticInfo.getCharacteristics().get(
+                        CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS);
+                Rect maxRegion = opticalBlackRegions[0];
+                for (Rect region : opticalBlackRegions) {
+                    if (region.width() * region.height() > maxRegion.width() * maxRegion.height()) {
+                        maxRegion = region;
+                    }
+                }
+
+                // Get average black pixel values in the region (region is multiple of 2x2)
+                Image.Plane rawPlane = rawImage.getPlanes()[0];
+                ByteBuffer rawBuffer = rawPlane.getBuffer();
+                float[] avgBlackLevels = {0, 0, 0, 0};
+                int rowSize = rawPlane.getRowStride() * rawPlane.getPixelStride();
+                int bytePerPixel = rawPlane.getPixelStride();
+                if (VERBOSE) {
+                    Log.v(TAG, "maxRegion: " + maxRegion + ", Row stride: " +
+                            rawPlane.getRowStride());
+                }
+                for (int row = maxRegion.left; row < maxRegion.right; row += 2) {
+                    for (int col = maxRegion.top; col < maxRegion.bottom; col += 2) {
+                        int startOffset = col * rawPlane.getRowStride() + row * bytePerPixel;
+                        avgBlackLevels[0] += rawBuffer.getShort(startOffset);
+                        avgBlackLevels[1] += rawBuffer.getShort(startOffset + bytePerPixel);
+                        startOffset += rowSize;
+                        avgBlackLevels[2] += rawBuffer.getShort(startOffset);
+                        avgBlackLevels[3] += rawBuffer.getShort(startOffset + bytePerPixel);
+                    }
+                }
+                int numBlackBlocks = maxRegion.width() * maxRegion.height() / (2 * 2);
+                for (int m = 0; m < avgBlackLevels.length; m++) {
+                    avgBlackLevels[m] /= numBlackBlocks;
+                }
+                opticalBlackLevels[i] = avgBlackLevels;
+
+                if (VERBOSE) {
+                    Log.v(TAG, String.format("Optical black level results for sensitivity (%d): %s",
+                            sensitivities[i], Arrays.toString(avgBlackLevels)));
+                }
+
+                rawImage.close();
+            } else {
+                changeExposure(previewBuilder, DEFAULT_EXP_TIME_NS, sensitivities[i]);
+                CaptureRequest previewRequest = previewBuilder.build();
+                mSession.capture(previewRequest, resultListener, mHandler);
+                result = resultListener.getCaptureResultForRequest(previewRequest,
+                        NUM_RESULTS_WAIT_TIMEOUT);
+            }
+
+            dynamicBlackLevels[i] = getValueNotNull(result,
+                    CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
+            dynamicWhiteLevels[i] = getValueNotNull(result,
+                    CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
+        }
+
+        if (VERBOSE) {
+            Log.v(TAG, "Different sensitivities tested: " + Arrays.toString(sensitivities));
+            Log.v(TAG, "Dynamic black level results: " + Arrays.deepToString(dynamicBlackLevels));
+            Log.v(TAG, "Dynamic white level results: " + Arrays.toString(dynamicWhiteLevels));
+            if (canCaptureBlackRaw) {
+                Log.v(TAG, "Optical black level results " +
+                        Arrays.deepToString(opticalBlackLevels));
+            }
+        }
+
+        // check the dynamic black level against global black level.
+        // Implicit guarantee: if the dynamic black level is supported, fixed black level must be
+        // supported as well (tested in ExtendedCameraCharacteristicsTest#testOpticalBlackRegions).
+        BlackLevelPattern blackPattern = mStaticInfo.getCharacteristics().get(
+                CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN);
+        int[] fixedBlackLevels = new int[4];
+        int fixedWhiteLevel = mStaticInfo.getCharacteristics().get(
+                CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL);
+        blackPattern.copyTo(fixedBlackLevels, 0);
+        float maxBlackDeviation = 0;
+        int maxWhiteDeviation = 0;
+        for (int i = 0; i < dynamicBlackLevels.length; i++) {
+            for (int j = 0; j < dynamicBlackLevels[i].length; j++) {
+                if (maxBlackDeviation < Math.abs(fixedBlackLevels[j] - dynamicBlackLevels[i][j])) {
+                    maxBlackDeviation = Math.abs(fixedBlackLevels[j] - dynamicBlackLevels[i][j]);
+                }
+            }
+            if (maxWhiteDeviation < Math.abs(dynamicWhiteLevels[i] - fixedWhiteLevel)) {
+                maxWhiteDeviation = Math.abs(dynamicWhiteLevels[i] - fixedWhiteLevel);
+            }
+        }
+        mCollector.expectLessOrEqual("Max deviation of the dynamic black level vs fixed black level"
+                + " exceed threshold."
+                + " Dynamic black level results: " + Arrays.deepToString(dynamicBlackLevels),
+                fixedBlackLevels[0] * DYNAMIC_VS_FIXED_BLK_WH_LVL_ERROR_MARGIN, maxBlackDeviation);
+        mCollector.expectLessOrEqual("Max deviation of the dynamic white level exceed threshold."
+                + " Dynamic white level results: " + Arrays.toString(dynamicWhiteLevels),
+                fixedWhiteLevel * DYNAMIC_VS_FIXED_BLK_WH_LVL_ERROR_MARGIN,
+                (float)maxWhiteDeviation);
+
+        // Validate against optical black levels if it is available
+        if (canCaptureBlackRaw) {
+            maxBlackDeviation = 0;
+            for (int i = 0; i < dynamicBlackLevels.length; i++) {
+                for (int j = 0; j < dynamicBlackLevels[i].length; j++) {
+                    if (maxBlackDeviation <
+                            Math.abs(opticalBlackLevels[i][j] - dynamicBlackLevels[i][j])) {
+                        maxBlackDeviation =
+                                Math.abs(opticalBlackLevels[i][j] - dynamicBlackLevels[i][j]);
+                    }
+                }
+            }
+
+            mCollector.expectLessOrEqual("Max deviation of the dynamic black level vs optical black"
+                    + " exceed threshold."
+                    + " Dynamic black level results: " + Arrays.deepToString(dynamicBlackLevels)
+                    + " Optical black level results: " + Arrays.deepToString(opticalBlackLevels),
+                    fixedBlackLevels[0] * DYNAMIC_VS_OPTICAL_BLK_LVL_ERROR_MARGIN,
+                    maxBlackDeviation);
+        }
+    }
+
     private void noiseReductionModeTestByCamera() throws Exception {
         Size maxPrevSize = mOrderedPreviewSizes.get(0);
         CaptureRequest.Builder requestBuilder =
@@ -2111,7 +2304,7 @@
      * @param result Result sensitivity
      */
     private void validateSensitivity(int request, int result) {
-        float sensitivityDelta = (float)(request - result);
+        float sensitivityDelta = request - result;
         float sensitivityErrorMargin = request * SENSITIVITY_ERROR_MARGIN_RATE;
         // First, round down not up, second, need close enough.
         mCollector.expectTrue("Sensitivity is invalid for AE manaul control test, request: "
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
index 2ae29c3..199552f 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -509,6 +509,12 @@
             waiverKeys.add(CaptureResult.CONTROL_AF_REGIONS);
         }
 
+        // Keys for dynamic black/white levels
+        if (!mStaticInfo.isOpticalBlackRegionSupported()) {
+            waiverKeys.add(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
+            waiverKeys.add(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
+        }
+
         if (mStaticInfo.isHardwareLevelFull()) {
             return waiverKeys;
         }
@@ -775,6 +781,8 @@
         resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_DATA);
         resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_MODE);
         resultKeys.add(CaptureResult.SENSOR_ROLLING_SHUTTER_SKEW);
+        resultKeys.add(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
+        resultKeys.add(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
         resultKeys.add(CaptureResult.SHADING_MODE);
         resultKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
         resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE);
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 28693c6..5b21e4d 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -24,6 +24,7 @@
 import android.hardware.camera2.CameraCharacteristics.Key;
 import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.cts.helpers.CameraErrorCollector;
 import android.hardware.camera2.params.BlackLevelPattern;
 import android.hardware.camera2.params.ColorSpaceTransform;
@@ -1181,6 +1182,82 @@
     }
 
     /**
+     * Sanity check of optical black regions.
+     */
+    public void testOpticalBlackRegions() {
+        int counter = 0;
+        for (CameraCharacteristics c : mCharacteristics) {
+            List<CaptureResult.Key<?>> resultKeys = c.getAvailableCaptureResultKeys();
+            boolean hasDynamicBlackLevel =
+                    resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
+            boolean hasDynamicWhiteLevel =
+                    resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
+            boolean hasFixedBlackLevel =
+                    c.getKeys().contains(CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN);
+            boolean hasFixedWhiteLevel =
+                    c.getKeys().contains(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL);
+            // The black and white levels should be either all supported or none of them is
+            // supported.
+            mCollector.expectTrue("Dynamic black and white level should be all or none of them"
+                    + " be supported", hasDynamicWhiteLevel == hasDynamicBlackLevel);
+            mCollector.expectTrue("Fixed black and white level should be all or none of them"
+                    + " be supported", hasFixedBlackLevel == hasFixedWhiteLevel);
+            mCollector.expectTrue("Fixed black level should be supported if dynamic black"
+                    + " level is supported", !hasDynamicBlackLevel || hasFixedBlackLevel);
+
+            if (c.getKeys().contains(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS)) {
+                // Regions shouldn't be null or empty.
+                Rect[] regions = CameraTestUtils.getValueNotNull(c,
+                        CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS);
+                CameraTestUtils.assertArrayNotEmpty(regions, "Optical back region arrays must not"
+                        + " be empty");
+
+                // Dynamic black level should be supported if the optical black region is
+                // advertised.
+                mCollector.expectTrue("Dynamic black and white level keys should be advertised in "
+                        + "available capture result key list", hasDynamicWhiteLevel);
+
+                // Range check.
+                for (Rect region : regions) {
+                    mCollector.expectTrue("Camera " + mIds[counter] + ": optical black region" +
+                            " shouldn't be empty!", !region.isEmpty());
+                    mCollector.expectGreaterOrEqual("Optical black region left", 0/*expected*/,
+                            region.left/*actual*/);
+                    mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/,
+                            region.top/*actual*/);
+                    mCollector.expectTrue("Optical black region left/right/width/height must be"
+                            + " even number, otherwise, the bayer CFA pattern in this region will"
+                            + " be messed up",
+                            region.left % 2 == 0 && region.top % 2 == 0 &&
+                            region.width() % 2 == 0 && region.height() % 2 == 0);
+                    mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/,
+                            region.top/*actual*/);
+                    Size size = CameraTestUtils.getValueNotNull(c,
+                            CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
+                    mCollector.expectLessOrEqual("Optical black region width",
+                            size.getWidth()/*expected*/, region.width());
+                    mCollector.expectLessOrEqual("Optical black region height",
+                            size.getHeight()/*expected*/, region.height());
+                    Rect activeArray = CameraTestUtils.getValueNotNull(c,
+                            CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+                    mCollector.expectTrue("Optical black region" + region + " should be outside of"
+                            + " active array " + activeArray,
+                            !region.intersect(activeArray));
+                    // Region need to be disjoint:
+                    for (Rect region2 : regions) {
+                        mCollector.expectTrue("Optical black region" + region + " should have no "
+                                + "overlap with " + region2,
+                                region == region2 || !region.intersect(region2));
+                    }
+                }
+            } else {
+                Log.i(TAG, "Camera " + mIds[counter] + " doesn't support optical black regions,"
+                        + " skip the region test");
+            }
+            counter++;
+        }
+    }
+    /**
      * Create an invalid size that's close to one of the good sizes in the list, but not one of them
      */
     private Size findInvalidSize(Size[] goodSizes) {
diff --git a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
index 9c783e0..1e9fe55 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -160,6 +160,20 @@
         }
     }
 
+    public void testRawPrivate() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing raw capture for camera " + id);
+                openDevice(id);
+
+                bufferFormatTestByCamera(ImageFormat.RAW_PRIVATE, /*repeating*/false);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+
     public void testRepeatingJpeg() throws Exception {
         for (String id : mCameraIds) {
             try {
@@ -185,6 +199,19 @@
         }
     }
 
+    public void testRepeatingRawPrivate() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing repeating raw capture for camera " + id);
+                openDevice(id);
+
+                bufferFormatTestByCamera(ImageFormat.RAW_PRIVATE, /*repeating*/true);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
     public void testLongProcessingRepeatingRaw() throws Exception {
         for (String id : mCameraIds) {
             try {
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index 39eb1dc..666292c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -16,7 +16,7 @@
 
 package android.hardware.camera2.cts;
 
-import static com.android.ex.camera2.blocking.BlockingSessionCallback.*;
+import static com.android.ex.camera2.blocking.BlockingSessionCallback.SESSION_CLOSED;
 
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraAccessException;
@@ -32,20 +32,20 @@
 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
 import android.hardware.camera2.params.InputConfiguration;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Size;
-import android.view.Surface;
-import android.cts.util.DeviceReportLog;
 import android.media.Image;
 import android.media.ImageReader;
 import android.media.ImageWriter;
 import android.os.ConditionVariable;
 import android.os.SystemClock;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
 
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.cts.util.Stat;
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
 
@@ -95,7 +95,7 @@
     @Override
     protected void tearDown() throws Exception {
         // Deliver the report to host will automatically clear the report log.
-        mReportLog.deliverReportToHost(getInstrumentation());
+        mReportLog.submit(getInstrumentation());
         super.tearDown();
     }
 
@@ -180,22 +180,22 @@
 
                 avgCameraLaunchTimes[counter] = Stat.getAverage(cameraLaunchTimes);
                 // Finish the data collection, report the KPIs.
-                mReportLog.printArray("Camera " + id
+                mReportLog.addValues("Camera " + id
                         + ": Camera open time", cameraOpenTimes,
                         ResultType.LOWER_BETTER, ResultUnit.MS);
-                mReportLog.printArray("Camera " + id
+                mReportLog.addValues("Camera " + id
                         + ": Camera configure stream time", configureStreamTimes,
                         ResultType.LOWER_BETTER, ResultUnit.MS);
-                mReportLog.printArray("Camera " + id
+                mReportLog.addValues("Camera " + id
                         + ": Camera start preview time", startPreviewTimes,
                         ResultType.LOWER_BETTER, ResultUnit.MS);
-                mReportLog.printArray("Camera " + id
+                mReportLog.addValues("Camera " + id
                         + ": Camera stop preview", stopPreviewTimes,
                         ResultType.LOWER_BETTER, ResultUnit.MS);
-                mReportLog.printArray("Camera " + id
+                mReportLog.addValues("Camera " + id
                         + ": Camera close time", cameraCloseTimes,
                         ResultType.LOWER_BETTER, ResultUnit.MS);
-                mReportLog.printArray("Camera " + id
+                mReportLog.addValues("Camera " + id
                         + ": Camera launch time", cameraLaunchTimes,
                         ResultType.LOWER_BETTER, ResultUnit.MS);
             }
@@ -205,7 +205,7 @@
             counter++;
         }
         if (mCameraIds.length != 0) {
-            mReportLog.printSummary("Camera launch average time for all cameras ",
+            mReportLog.setSummary("Camera launch average time for all cameras ",
                     Stat.getAverage(avgCameraLaunchTimes), ResultType.LOWER_BETTER, ResultUnit.MS);
         }
     }
@@ -297,19 +297,19 @@
                     // simulate real scenario (preview runs a bit)
                     waitForNumResults(previewResultListener, NUM_RESULTS_WAIT);
 
-                    blockingStopPreview();
+                    stopPreview();
 
                 }
-                mReportLog.printArray("Camera " + id
+                mReportLog.addValues("Camera " + id
                         + ": Camera capture latency", captureTimes,
                         ResultType.LOWER_BETTER, ResultUnit.MS);
                 // If any of the partial results do not contain AE and AF state, then no report
                 if (isPartialTimingValid) {
-                    mReportLog.printArray("Camera " + id
+                    mReportLog.addValues("Camera " + id
                             + ": Camera partial result latency", getPartialTimes,
                             ResultType.LOWER_BETTER, ResultUnit.MS);
                 }
-                mReportLog.printArray("Camera " + id
+                mReportLog.addValues("Camera " + id
                         + ": Camera capture result latency", getResultTimes,
                         ResultType.LOWER_BETTER, ResultUnit.MS);
 
@@ -324,7 +324,7 @@
 
         // Result will not be reported in CTS report if no summary is printed.
         if (mCameraIds.length != 0) {
-            mReportLog.printSummary("Camera capture result average latency for all cameras ",
+            mReportLog.setSummary("Camera capture result average latency for all cameras ",
                     Stat.getAverage(avgResultTimes), ResultType.LOWER_BETTER, ResultUnit.MS);
         }
     }
@@ -481,13 +481,13 @@
             reprocessType = " opaque reprocessing ";
         }
 
-        mReportLog.printArray("Camera " + mCamera.getId()
+        mReportLog.addValues("Camera " + mCamera.getId()
                 + ":" + reprocessType + " max capture timestamp gaps", maxCaptureGapsMs,
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        mReportLog.printArray("Camera " + mCamera.getId()
+        mReportLog.addValues("Camera " + mCamera.getId()
                 + ":" + reprocessType + "capture average frame duration", averageFrameDurationMs,
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        mReportLog.printSummary("Camera reprocessing average max capture timestamp gaps for Camera "
+        mReportLog.setSummary("Camera reprocessing average max capture timestamp gaps for Camera "
                 + mCamera.getId(), Stat.getAverage(maxCaptureGapsMs), ResultType.LOWER_BETTER,
                 ResultUnit.MS);
 
@@ -575,17 +575,17 @@
 
         // Report the performance data
         if (asyncMode) {
-            mReportLog.printArray("Camera " + mCamera.getId()
+            mReportLog.addValues("Camera " + mCamera.getId()
                     + ":" + reprocessType + "capture latency", getImageLatenciesMs,
                     ResultType.LOWER_BETTER, ResultUnit.MS);
-            mReportLog.printSummary("Camera reprocessing average latency for Camera " +
+            mReportLog.setSummary("Camera reprocessing average latency for Camera " +
                     mCamera.getId(), Stat.getAverage(getImageLatenciesMs), ResultType.LOWER_BETTER,
                     ResultUnit.MS);
         } else {
-            mReportLog.printArray("Camera " + mCamera.getId()
+            mReportLog.addValues("Camera " + mCamera.getId()
                     + ":" + reprocessType + "shot to shot latency", getImageLatenciesMs,
                     ResultType.LOWER_BETTER, ResultUnit.MS);
-            mReportLog.printSummary("Camera reprocessing shot to shot average latency for Camera " +
+            mReportLog.setSummary("Camera reprocessing shot to shot average latency for Camera " +
                     mCamera.getId(), Stat.getAverage(getImageLatenciesMs), ResultType.LOWER_BETTER,
                     ResultUnit.MS);
         }
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index feade79..4acbffe 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -104,7 +104,7 @@
         super.tearDown();
     }
 
-    private void doBasicRecording() throws Exception {
+    private void doBasicRecording(boolean useVideoStab) throws Exception {
         for (int i = 0; i < mCameraIds.length; i++) {
             try {
                 Log.i(TAG, "Testing basic recording for camera " + mCameraIds[i]);
@@ -116,9 +116,17 @@
                             " does not support color outputs, skipping");
                     continue;
                 }
+
+                if (!mStaticInfo.isVideoStabilizationSupported() && useVideoStab) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support video stabilization, skipping the stabilization"
+                            + " test");
+                    continue;
+                }
+
                 initSupportedVideoSize(mCameraIds[i]);
 
-                basicRecordingTestByCamera(mCamcorderProfileList);
+                basicRecordingTestByCamera(mCamcorderProfileList, useVideoStab);
             } finally {
                 closeDevice();
                 releaseRecorder();
@@ -128,6 +136,23 @@
 
     /**
      * <p>
+     * Test basic video stabilitzation camera recording.
+     * </p>
+     * <p>
+     * This test covers the typical basic use case of camera recording with video
+     * stabilization is enabled, if video stabilization is supported.
+     * MediaRecorder is used to record the audio and video, CamcorderProfile is
+     * used to configure the MediaRecorder. It goes through the pre-defined
+     * CamcorderProfile list, test each profile configuration and validate the
+     * recorded video. Preview is set to the video size.
+     * </p>
+     */
+    public void testBasicVideoStabilizationRecording() throws Exception {
+        doBasicRecording(/*useVideoStab*/true);
+    }
+
+    /**
+     * <p>
      * Test basic camera recording.
      * </p>
      * <p>
@@ -139,7 +164,7 @@
      * </p>
      */
     public void testBasicRecording() throws Exception {
-        doBasicRecording();
+        doBasicRecording(/*useVideoStab*/false);
     }
 
     /**
@@ -159,7 +184,7 @@
         assertNotNull("Failed to create persistent input surface!", mPersistentSurface);
 
         try {
-            doBasicRecording();
+            doBasicRecording(/*useVideoStab*/false);
         } finally {
             mPersistentSurface.release();
             mPersistentSurface = null;
@@ -311,7 +336,7 @@
                 }
 
                 int camcorderProfileList[] = new int[] {minFpsProfileId, maxFpsProfileId};
-                basicRecordingTestByCamera(camcorderProfileList);
+                basicRecordingTestByCamera(camcorderProfileList, /*useVideoStab*/false);
             } finally {
                 closeDevice();
                 releaseRecorder();
@@ -594,7 +619,8 @@
      * Test camera recording by using each available CamcorderProfile for a
      * given camera. preview size is set to the video size.
      */
-    private void basicRecordingTestByCamera(int[] camcorderProfileList) throws Exception {
+    private void basicRecordingTestByCamera(int[] camcorderProfileList, boolean useVideoStab)
+            throws Exception {
         Size maxPreviewSize = mOrderedPreviewSizes.get(0);
         List<Range<Integer> > fpsRanges = Arrays.asList(
                 mStaticInfo.getAeAvailableTargetFpsRangesChecked());
@@ -643,7 +669,7 @@
 
             // Start recording
             SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
-            startRecording(/* useMediaRecorder */true, resultListener);
+            startRecording(/* useMediaRecorder */true, resultListener, useVideoStab);
 
             // Record certain duration.
             SystemClock.sleep(RECORDING_DURATION_MS);
@@ -698,7 +724,7 @@
 
             // Start recording
             SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
-            startRecording(/* useMediaRecorder */true, resultListener);
+            startRecording(/* useMediaRecorder */true, resultListener, /*useVideoStab*/false);
 
             // Record certain duration.
             SystemClock.sleep(RECORDING_DURATION_MS);
@@ -920,7 +946,7 @@
                 CaptureRequest request = videoSnapshotRequestBuilder.build();
 
                 // Start recording
-                startRecording(/* useMediaRecorder */true, resultListener);
+                startRecording(/* useMediaRecorder */true, resultListener, /*useVideoStab*/false);
                 long startTime = SystemClock.elapsedRealtime();
 
                 // Record certain duration.
@@ -1111,7 +1137,11 @@
     }
 
     private void startRecording(boolean useMediaRecorder,
-            CameraCaptureSession.CaptureCallback listener) throws Exception {
+            CameraCaptureSession.CaptureCallback listener, boolean useVideoStab) throws Exception {
+        if (!mStaticInfo.isVideoStabilizationSupported() && useVideoStab) {
+            throw new IllegalArgumentException("Video stabilization is not supported");
+        }
+
         List<Surface> outputSurfaces = new ArrayList<Surface>(2);
         assertTrue("Both preview and recording surfaces should be valid",
                 mPreviewSurface.isValid() && mRecordingSurface.isValid());
@@ -1129,6 +1159,10 @@
         // Make sure camera output frame rate is set to correct value.
         Range<Integer> fpsRange = Range.create(mVideoFrameRate, mVideoFrameRate);
         recordingRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
+        if (useVideoStab) {
+            recordingRequestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE,
+                    CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON);
+        }
         recordingRequestBuilder.addTarget(mRecordingSurface);
         recordingRequestBuilder.addTarget(mPreviewSurface);
         mSession.setRepeatingRequest(recordingRequestBuilder.build(), listener, mHandler);
@@ -1142,7 +1176,7 @@
     }
 
     private void startRecording(boolean useMediaRecorder)  throws Exception {
-        startRecording(useMediaRecorder, null);
+        startRecording(useMediaRecorder, /*listener*/null, /*useVideoStab*/false);
     }
 
     private void stopCameraStreaming() throws Exception {
diff --git a/tests/camera/src/android/hardware/camera2/cts/StaticMetadataCollectionTest.java b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataCollectionTest.java
index 145c2d1..4f4c5fe 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StaticMetadataCollectionTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataCollectionTest.java
@@ -17,13 +17,13 @@
 package android.hardware.camera2.cts;
 
 import android.content.pm.PackageManager;
-import android.cts.util.DeviceReportLog;
 import android.hardware.camera2.cts.helpers.CameraMetadataGetter;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
 import android.util.Log;
 
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
 
 import org.json.JSONArray;
 import org.json.JSONObject;
@@ -48,7 +48,7 @@
     @Override
     protected void tearDown() throws Exception {
         // Deliver the report to host will automatically clear the report log.
-        mReportLog.deliverReportToHost(getInstrumentation());
+        mReportLog.submit(getInstrumentation());
         super.tearDown();
     }
 
@@ -80,7 +80,7 @@
                 Log.e(TAG, "Unable to close camera info getter " + e.getMessage());
             }
 
-            mReportLog.printSummary("Camera data collection for static info and capture request"
+            mReportLog.setSummary("Camera data collection for static info and capture request"
                     + " templates",
                     0.0, ResultType.NEUTRAL, ResultUnit.NONE);
         }
@@ -88,11 +88,11 @@
     }
 
     private void dumpDoubleAsCtsResult(String name, double value) {
-        mReportLog.printValue(name, value, ResultType.NEUTRAL, ResultUnit.NONE);
+        mReportLog.addValue(name, value, ResultType.NEUTRAL, ResultUnit.NONE);
     }
 
     public void dumpDoubleArrayAsCtsResult(String name, double[] values) {
-        mReportLog.printArray(name, values, ResultType.NEUTRAL, ResultUnit.NONE);
+        mReportLog.addValues(name, values, ResultType.NEUTRAL, ResultUnit.NONE);
     }
 
     private double getJsonValueAsDouble(String name, Object obj) throws Exception {
diff --git a/tests/camera/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index e892e42..cb6b04c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/camera/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -1626,6 +1626,13 @@
         return modes;
     }
 
+    public boolean isVideoStabilizationSupported() {
+        Integer[] videoStabModes =
+                CameraTestUtils.toObject(getAvailableVideoStabilizationModesChecked());
+        return Arrays.asList(videoStabModes).contains(
+                CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
+    }
+
     /**
      * Get availableOpticalStabilization and do the sanity check.
      *
@@ -2195,6 +2202,25 @@
     }
 
     /**
+     * Check if optical black regions key is supported.
+     */
+    public boolean isOpticalBlackRegionSupported() {
+        return areKeysAvailable(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS);
+    }
+
+    /**
+     * Check if the dynamic black level is supported.
+     *
+     * <p>
+     * Note that: This also indicates if the white level is supported, as dynamic black and white
+     * level must be all supported or none of them is supported.
+     * </p>
+     */
+    public boolean isDynamicBlackLevelSupported() {
+        return areKeysAvailable(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
+    }
+
+    /**
      * Get the value in index for a fixed-size array from a given key.
      *
      * <p>If the camera device is incorrectly reporting values, log a warning and return
diff --git a/tests/deviceadmin/Android.mk b/tests/deviceadmin/Android.mk
deleted file mode 100644
index 2e89d34..0000000
--- a/tests/deviceadmin/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_JAVA_LIBRARIES := guava
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsDeviceAdmin
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/deviceadmin/AndroidManifest.xml b/tests/deviceadmin/AndroidManifest.xml
deleted file mode 100644
index f70a677..0000000
--- a/tests/deviceadmin/AndroidManifest.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.deviceadmin.cts">
-    <application>
-
-        <uses-library android:name="android.test.runner"/>
-
-        <receiver android:name="android.deviceadmin.cts.CtsDeviceAdminReceiver"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
-            <meta-data android:name="android.app.device_admin"
-                    android:resource="@xml/device_admin" />
-            <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
-            </intent-filter>
-        </receiver>
-        
-        <receiver android:name="android.deviceadmin.cts.CtsDeviceAdminReceiver2"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
-            <meta-data android:name="android.app.device_admin"
-                    android:resource="@xml/device_admin_2" />
-            <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
-            </intent-filter>
-        </receiver>
-
-        <!-- Device Admin that needs to be in the deactivated state in order
-             for tests to pass. -->
-        <receiver android:name="android.deviceadmin.cts.CtsDeviceAdminDeactivatedReceiver"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
-            <meta-data android:name="android.app.device_admin"
-                    android:resource="@xml/device_admin" />
-            <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
-            </intent-filter>
-        </receiver>
-
-        <!-- Helper Activity used by Device Admin activation tests -->
-        <activity android:name="android.deviceadmin.cts.CtsDeviceAdminActivationTestActivity"
-                android:label="Device Admin activation test" />
-
-        <!-- Broken device admin: meta-data missing -->
-        <receiver android:name="android.deviceadmin.cts.CtsDeviceAdminBrokenReceiver"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
-            <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
-            </intent-filter>
-        </receiver>
-
-        <!-- Broken device admin: filter doesn't match an Intent with action
-             android.app.action.DEVICE_ADMIN_ENABLED and nothing else (e.g.,
-             data) set -->
-        <receiver android:name="android.deviceadmin.cts.CtsDeviceAdminBrokenReceiver2"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
-            <meta-data android:name="android.app.device_admin"
-                    android:resource="@xml/device_admin" />
-            <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
-                <data android:scheme="https" />
-            </intent-filter>
-        </receiver>
-
-        <!-- Broken device admin: meta-data element doesn't point to valid
-             Device Admin configuration/description -->
-        <receiver android:name="android.deviceadmin.cts.CtsDeviceAdminBrokenReceiver3"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
-            <meta-data android:name="android.app.device_admin"
-                    android:resource="@xml/broken_device_admin" />
-            <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
-            </intent-filter>
-        </receiver>
-
-        <!-- Broken device admin: filter doesn't match Intents with action
-             android.app.action.DEVICE_ADMIN_ENABLED -->
-        <receiver android:name="android.deviceadmin.cts.CtsDeviceAdminBrokenReceiver4"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
-            <meta-data android:name="android.app.device_admin"
-                    android:resource="@xml/device_admin" />
-            <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_DISABLED" />
-            </intent-filter>
-        </receiver>
-
-        <!-- Broken device admin: no intent-filter -->
-        <receiver android:name="android.deviceadmin.cts.CtsDeviceAdminBrokenReceiver5"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
-            <meta-data android:name="android.app.device_admin"
-                    android:resource="@xml/device_admin" />
-        </receiver>
-
-    </application>
-
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.admin"
-            android:label="Tests for the device admin APIs."/>
-</manifest>
diff --git a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminActivationTestActivity.java b/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminActivationTestActivity.java
deleted file mode 100644
index 1779ec8..0000000
--- a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminActivationTestActivity.java
+++ /dev/null
@@ -1,64 +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 android.deviceadmin.cts;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.WindowManager;
-
-import com.google.common.annotations.VisibleForTesting;
-
-/**
- * Helper {@link Activity} for CTS tests of Device Admin activation. The {@code Activity}
- * enables tests to capture the invocations of its {@link #onActivityResult(int, int, Intent)} by
- * providing a {@link OnActivityResultListener}.
- */
-public class CtsDeviceAdminActivationTestActivity extends Activity {
-    public interface OnActivityResultListener {
-        void onActivityResult(int requestCode, int resultCode, Intent data);
-    }
-
-    private OnActivityResultListener mOnActivityResultListener;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        // Dismiss keyguard and keep screen on while this Activity is displayed.
-        // This is needed because on older platforms, when the keyguard is on, onActivityResult is
-        // not invoked when a Device Admin activation is rejected without user interaction.
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
-                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
-                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-    }
-
-    @VisibleForTesting
-    public void setOnActivityResultListener(OnActivityResultListener listener) {
-        mOnActivityResultListener = listener;
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (mOnActivityResultListener != null) {
-            mOnActivityResultListener.onActivityResult(requestCode, resultCode, data);
-            return;
-        }
-
-        super.onActivityResult(requestCode, resultCode, data);
-    }
-}
diff --git a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver.java b/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver.java
deleted file mode 100644
index f64c6b6..0000000
--- a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver.java
+++ /dev/null
@@ -1,22 +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 android.deviceadmin.cts;
-
-import android.app.admin.DeviceAdminReceiver;
-
-public class CtsDeviceAdminBrokenReceiver extends DeviceAdminReceiver {
-}
diff --git a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver2.java b/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver2.java
deleted file mode 100644
index 492a7cb..0000000
--- a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver2.java
+++ /dev/null
@@ -1,22 +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 android.deviceadmin.cts;
-
-import android.app.admin.DeviceAdminReceiver;
-
-public class CtsDeviceAdminBrokenReceiver2 extends DeviceAdminReceiver {
-}
diff --git a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver3.java b/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver3.java
deleted file mode 100644
index 92bc878..0000000
--- a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver3.java
+++ /dev/null
@@ -1,22 +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 android.deviceadmin.cts;
-
-import android.app.admin.DeviceAdminReceiver;
-
-public class CtsDeviceAdminBrokenReceiver3 extends DeviceAdminReceiver {
-}
diff --git a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver4.java b/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver4.java
deleted file mode 100644
index 53f15a7..0000000
--- a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver4.java
+++ /dev/null
@@ -1,22 +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 android.deviceadmin.cts;
-
-import android.app.admin.DeviceAdminReceiver;
-
-public class CtsDeviceAdminBrokenReceiver4 extends DeviceAdminReceiver {
-}
diff --git a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver5.java b/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver5.java
deleted file mode 100644
index 2dc7100..0000000
--- a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminBrokenReceiver5.java
+++ /dev/null
@@ -1,22 +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 android.deviceadmin.cts;
-
-import android.app.admin.DeviceAdminReceiver;
-
-public class CtsDeviceAdminBrokenReceiver5 extends DeviceAdminReceiver {
-}
diff --git a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminDeactivatedReceiver.java b/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminDeactivatedReceiver.java
deleted file mode 100644
index ec59f63..0000000
--- a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminDeactivatedReceiver.java
+++ /dev/null
@@ -1,22 +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 android.deviceadmin.cts;
-
-import android.app.admin.DeviceAdminReceiver;
-
-public class CtsDeviceAdminDeactivatedReceiver extends DeviceAdminReceiver {
-}
diff --git a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminReceiver.java b/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminReceiver.java
deleted file mode 100644
index 43485d7..0000000
--- a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminReceiver.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 android.deviceadmin.cts;
-
-import android.app.admin.DeviceAdminReceiver;
-
-public class CtsDeviceAdminReceiver extends DeviceAdminReceiver {
-}
diff --git a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminReceiver2.java b/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminReceiver2.java
deleted file mode 100644
index eadf31b..0000000
--- a/tests/deviceadmin/src/android/deviceadmin/cts/CtsDeviceAdminReceiver2.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 android.deviceadmin.cts;
-
-import android.app.admin.DeviceAdminReceiver;
-
-public class CtsDeviceAdminReceiver2 extends DeviceAdminReceiver {
-}
diff --git a/tests/dram/Android.mk b/tests/dram/Android.mk
new file mode 100644
index 0000000..e7cd0bb
--- /dev/null
+++ b/tests/dram/Android.mk
@@ -0,0 +1,39 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+
+# Include both the 32 and 64 bit versions
+LOCAL_MULTILIB := both
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+
+LOCAL_JNI_SHARED_LIBRARIES := libctsdram_jni
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsDramTestCases
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := 16
+
+include $(BUILD_CTS_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/dram/AndroidManifest.xml b/tests/dram/AndroidManifest.xml
new file mode 100644
index 0000000..d43fe79
--- /dev/null
+++ b/tests/dram/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.dram.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="android.dram.cts"
+            android:label="DRAM bandwidth measurement" />
+</manifest>
diff --git a/tests/dram/AndroidTest.xml b/tests/dram/AndroidTest.xml
new file mode 100644
index 0000000..019c15d
--- /dev/null
+++ b/tests/dram/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Dram test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsDramTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.dram.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/suite/cts/deviceTests/dram/jni/Android.mk b/tests/dram/jni/Android.mk
similarity index 100%
rename from suite/cts/deviceTests/dram/jni/Android.mk
rename to tests/dram/jni/Android.mk
diff --git a/tests/dram/jni/MemoryNativeJni.cpp b/tests/dram/jni/MemoryNativeJni.cpp
new file mode 100644
index 0000000..cbf145c
--- /dev/null
+++ b/tests/dram/jni/MemoryNativeJni.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#include <jni.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+double currentTimeMillis()
+{
+    struct timeval tv;
+    gettimeofday(&tv, (struct timezone *) NULL);
+    return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
+}
+
+extern "C" JNIEXPORT jdouble JNICALL Java_android_dram_cts_MemoryNative_runMemcpy(JNIEnv* env,
+        jclass clazz, jint bufferSize, jint repetition)
+{
+    char* src = new char[bufferSize];
+    char* dst = new char[bufferSize];
+    if ((src == NULL) || (dst == NULL)) {
+        delete[] src;
+        delete[] dst;
+        env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), "No memory");
+        return -1;
+    }
+    memset(src, 0, bufferSize);
+    memset(dst, 0, bufferSize);
+    double start = currentTimeMillis();
+    for (int i = 0; i < repetition; i++) {
+        memcpy(dst, src, bufferSize);
+        src[bufferSize - 1] = i & 0xff;
+    }
+    double end = currentTimeMillis();
+    delete[] src;
+    delete[] dst;
+    return end - start;
+}
+
+extern "C" JNIEXPORT jdouble JNICALL Java_android_dram_cts_MemoryNative_runMemset(JNIEnv* env,
+        jclass clazz, jint bufferSize, jint repetition, jint c)
+{
+    char* dst = new char[bufferSize];
+    if (dst == NULL) {
+        delete[] dst;
+        env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), "No memory");
+        return -1;
+    }
+    memset(dst, 0, bufferSize);
+    double start = currentTimeMillis();
+    for (int i = 0; i < repetition; i++) {
+        memset(dst, (c + i) & 0xff, bufferSize);
+    }
+    double end = currentTimeMillis();
+    delete[] dst;
+    return end - start;
+}
+
diff --git a/tests/dram/src/android/dram/cts/BandwidthTest.java b/tests/dram/src/android/dram/cts/BandwidthTest.java
new file mode 100644
index 0000000..2096402
--- /dev/null
+++ b/tests/dram/src/android/dram/cts/BandwidthTest.java
@@ -0,0 +1,225 @@
+/*
+ * 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 android.dram.cts;
+
+import android.content.Context;
+import android.cts.util.CtsAndroidTestCase;
+import android.graphics.Point;
+import android.util.Log;
+import android.view.WindowManager;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+
+/**
+ * check how many screens the memcpy function can copy in a sec.
+ * Note that this does not represent the total memory bandwidth available in the system
+ * as typically CPU cannot use the whole bandwidth.
+ * Smaller buffers can fit into L1 or L2 cache, which can show big boost.
+ */
+public class BandwidthTest extends CtsAndroidTestCase {
+    private static final String TAG = BandwidthTest.class.getSimpleName();
+    private static final int MEMCPY_REPETITION = 10;
+    private static final int MEMSET_REPETITION = 30;
+    private static final int REPEAT_IN_EACH_CALL = 100;
+    private static final int KB = 1024;
+    private static final int MB = 1024 * 1024;
+    private static final int MEMSET_CHAR = 0xa5;
+    // reject data outside +/- this value * median
+    private static final double OUTLIER_THRESHOLD = 0.1;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // warm-up
+        MemoryNative.runMemcpy(2 * MB, 100);
+    }
+
+    public void testMemcpyK004() {
+        doRunMemcpy(4 * KB);
+    }
+
+    public void testMemcpyK008() {
+        doRunMemcpy(8 * KB);
+    }
+
+    public void testMemcpyK016() {
+        doRunMemcpy(16 * KB);
+    }
+
+    public void testMemcpyK032() {
+        doRunMemcpy(32 * KB);
+    }
+
+    public void testMemcpyK064() {
+        doRunMemcpy(64 * KB);
+    }
+
+    public void testMemcpyK128() {
+        doRunMemcpy(128 * KB);
+    }
+
+    public void testMemcpyK256() {
+        doRunMemcpy(256 * KB);
+    }
+
+    public void testMemcpyK512() {
+        doRunMemcpy(512 * KB);
+    }
+
+    public void testMemcpyM001() {
+        doRunMemcpy(1 * MB);
+    }
+
+    public void testMemcpyM002() {
+        doRunMemcpy(2 * MB);
+    }
+
+    public void testMemcpyM004() {
+        doRunMemcpy(4 * MB);
+    }
+
+    public void testMemcpyM008() {
+        doRunMemcpy(8 * MB);
+    }
+
+    public void testMemcpyM016() {
+        doRunMemcpy(16 * MB);
+    }
+
+    public void testMemsetK004() {
+        doRunMemset(4 * KB);
+    }
+
+    public void testMemsetK008() {
+        doRunMemset(8 * KB);
+    }
+
+    public void testMemsetK016() {
+        doRunMemset(16 * KB);
+    }
+
+    public void testMemsetK032() {
+        doRunMemset(32 * KB);
+    }
+
+    public void testMemsetK064() {
+        doRunMemset(64 * KB);
+    }
+
+    public void testMemsetK128() {
+        doRunMemset(128 * KB);
+    }
+
+    public void testMemsetK256() {
+        doRunMemset(256 * KB);
+    }
+
+    public void testMemsetK512() {
+        doRunMemset(512 * KB);
+    }
+
+    public void testMemsetM001() {
+        doRunMemset(1 * MB);
+    }
+
+    public void testMemsetM002() {
+        doRunMemset(2 * MB);
+    }
+
+    public void testMemsetM004() {
+        doRunMemset(4 * MB);
+    }
+
+    public void testMemsetM008() {
+        doRunMemset(8 * MB);
+    }
+
+    public void testMemsetM016() {
+        doRunMemset(16 * MB);
+    }
+
+    private void doRunMemcpy(int bufferSize) {
+        double[] result = new double[MEMCPY_REPETITION];
+        int repeatInEachCall = REPEAT_IN_EACH_CALL;
+        if (bufferSize < (1 * MB)) {
+            // too small buffer size finishes too early to give accurate result.
+            repeatInEachCall *= (1 * MB / bufferSize);
+        }
+        for (int i = 0; i < MEMCPY_REPETITION; i++) {
+            result[i] = MemoryNative.runMemcpy(bufferSize, repeatInEachCall);
+        }
+        DeviceReportLog report = new DeviceReportLog();
+        report.addValues("memcpy time", result, ResultType.LOWER_BETTER,
+                ResultUnit.MS);
+        double[] mbps = Stat.calcRatePerSecArray(
+                (double)bufferSize * repeatInEachCall / 1024.0 / 1024.0, result);
+        report.addValues("memcpy throughput", mbps, ResultType.HIGHER_BETTER,
+                ResultUnit.MBPS);
+        Stat.StatResult stat = Stat.getStatWithOutlierRejection(mbps, OUTLIER_THRESHOLD);
+        if (stat.mDataCount != result.length) {
+            Log.w(TAG, "rejecting " + (result.length - stat.mDataCount) + " outliers");
+        }
+        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+        Point size = new Point();
+        wm.getDefaultDisplay().getSize(size);
+        Log.i(TAG, " x " + size.x + " y " + size.y);
+        double pixels = size.x * size.y;
+        // now this represents how many times the whole screen can be copied in a sec.
+        double screensPerSecAverage = stat.mAverage / pixels * 1024.0 * 1024.0 / 4.0;
+        report.addValue("memcpy in fps", screensPerSecAverage,
+                ResultType.HIGHER_BETTER, ResultUnit.FPS);
+        report.setSummary("memcpy throughput", stat.mAverage, ResultType.HIGHER_BETTER,
+                ResultUnit.MBPS);
+        report.submit(getInstrumentation());
+    }
+
+    private void doRunMemset(int bufferSize) {
+        double[] result = new double[MEMSET_REPETITION];
+        int repeatInEachCall = REPEAT_IN_EACH_CALL;
+        if (bufferSize < (1 * MB)) {
+            // too small buffer size finishes too early to give accurate result.
+            repeatInEachCall *= (1 * MB / bufferSize);
+        }
+        for (int i = 0; i < MEMSET_REPETITION; i++) {
+            result[i] = MemoryNative.runMemset(bufferSize, repeatInEachCall, MEMSET_CHAR);
+        }
+        DeviceReportLog report = new DeviceReportLog();
+        report.addValues("memset time", result, ResultType.LOWER_BETTER, ResultUnit.MS);
+        double[] mbps = Stat.calcRatePerSecArray(
+                (double)bufferSize * repeatInEachCall / 1024.0 / 1024.0, result);
+        report.addValues("memset throughput", mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
+        Stat.StatResult stat = Stat.getStatWithOutlierRejection(mbps, OUTLIER_THRESHOLD);
+        if (stat.mDataCount != result.length) {
+            Log.w(TAG, "rejecting " + (result.length - stat.mDataCount) + " outliers");
+        }
+        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+        Point size = new Point();
+        wm.getDefaultDisplay().getSize(size);
+        Log.i(TAG, " x " + size.x + " y " + size.y);
+        double pixels = size.x * size.y;
+        // now this represents how many times the whole screen can be copied in a sec.
+        double screensPerSecAverage = stat.mAverage / pixels * 1024.0 * 1024.0 / 4.0;
+        report.addValue("memset in fps", screensPerSecAverage,
+                ResultType.HIGHER_BETTER, ResultUnit.FPS);
+        report.setSummary("memset throughput", stat.mAverage, ResultType.HIGHER_BETTER,
+                ResultUnit.MBPS);
+        report.submit(getInstrumentation());
+    }
+}
diff --git a/tests/dram/src/android/dram/cts/MemoryNative.java b/tests/dram/src/android/dram/cts/MemoryNative.java
new file mode 100644
index 0000000..7fa4c46
--- /dev/null
+++ b/tests/dram/src/android/dram/cts/MemoryNative.java
@@ -0,0 +1,41 @@
+/*
+ * 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 android.dram.cts;
+
+public class MemoryNative {
+    static {
+        System.loadLibrary("ctsdram_jni");
+    }
+    /**
+     * run memcpy for given number of repetition from a source to a destination buffers
+     * with each having the size of bufferSize.
+     * @param bufferSize
+     * @param repetition
+     * @return time spent in copying in ms.
+     */
+    public static native double runMemcpy(int bufferSize, int repetition);
+
+    /**
+     * run memset for given number of repetition from a source to a destination buffers
+     * with each having the size of bufferSize.
+     * @param bufferSize
+     * @param repetition
+     * @param c char to set. Only LSBs will be used to get char value.
+     * @return time spent in memset in ms.
+     */
+    public static native double runMemset(int bufferSize, int repetition, int c);
+}
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index acab74e..8e8981b 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -237,14 +237,6 @@
   bug: 17989532
 },
 {
-  description: "The new long processing test is not yet passing on all devices",
-  names: [
-    "android.hardware.camera2.cts.ImageReaderTest#testLongProcessingRepeatingRaw",
-    "android.hardware.camera2.cts.ImageReaderTest#testLongProcessingRepeatingFlexibleYuv"
-  ],
-  bug: 22861512
-},
-{
   description: "The timing measurements for preview callbacks are not reliable",
   names: [
     "android.hardware.cts.CameraTest#testPreviewFpsRange"
@@ -254,7 +246,7 @@
 {
   description: "Light status bar CTS coming in late",
   names: [
-    "com.android.cts.systemui.LightStatusBarTests#testLightStatusBarIcons"
+    "android.systemui.cts.LightStatusBarTests#testLightStatusBarIcons"
   ],
   bug: 23427621
 },
@@ -359,10 +351,17 @@
   bug: 25652250
 },
 {
-  description: "Wired headset tests are no longer a requirement per CDD",
+  description: "unit testing for MediaPreparer lives within mediastress module",
   names: [
-    "android.telecom.cts.WiredHeadsetTest"
+    "android.mediastress.cts.preconditions.MediaPreparerTest"
   ],
-  bug: 26149528
+  bug: 25850508
+},
+{
+  description: "Tests for the signature tests should not be in CTS",
+  names: [
+    "android.signature.cts.tests"
+  ],
+  bug: 26150806
 }
 ]
diff --git a/tests/filesystem/Android.mk b/tests/filesystem/Android.mk
new file mode 100644
index 0000000..00e5ee7
--- /dev/null
+++ b/tests/filesystem/Android.mk
@@ -0,0 +1,33 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsFileSystemTestCases
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := 16
+
+include $(BUILD_CTS_PACKAGE)
+
diff --git a/tests/filesystem/AndroidManifest.xml b/tests/filesystem/AndroidManifest.xml
new file mode 100644
index 0000000..c02ac77
--- /dev/null
+++ b/tests/filesystem/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.filesystem.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="android.filesystem.cts"
+            android:label="CTS tests for file system" />
+</manifest>
diff --git a/tests/filesystem/AndroidTest.xml b/tests/filesystem/AndroidTest.xml
new file mode 100644
index 0000000..1962357
--- /dev/null
+++ b/tests/filesystem/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS File System test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsFileSystemTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.filesystem.cts" />
+        <option name="runtime-hint" value="9m" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/filesystem/src/android/filesystem/cts/AlmostFullTest.java b/tests/filesystem/src/android/filesystem/cts/AlmostFullTest.java
new file mode 100644
index 0000000..991f9bf
--- /dev/null
+++ b/tests/filesystem/src/android/filesystem/cts/AlmostFullTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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 android.filesystem.cts;
+
+import android.util.Log;
+
+import android.cts.util.CtsAndroidTestCase;
+import android.cts.util.SystemUtil;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.cts.util.TimeoutReq;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class AlmostFullTest extends CtsAndroidTestCase {
+
+    private static final String DIR_INITIAL_FILL = "INITIAL_FILL";
+    private static final String DIR_SEQ_UPDATE = "SEQ_UPDATE";
+    private static final String DIR_RANDOM_WR = "RANDOM_WR";
+    private static final String DIR_RANDOM_RD = "RANDOM_RD";
+    private static final String TAG = "AlmostFullTest";
+
+    private static final long FREE_SPACE_FINAL = 1000L * 1024 * 1024L;
+
+    // test runner creates multiple instances at the begging.
+    // use that to fill disk only once.
+    // set as final to initialize it only once
+    private static final AtomicInteger mRefCounter = new AtomicInteger(0);
+    private static final AtomicBoolean mDiskFilled = new AtomicBoolean(false);
+
+    public AlmostFullTest() {
+        int currentCounter = mRefCounter.incrementAndGet();
+        Log.i(TAG, "++currentCounter: " + currentCounter);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        if (mDiskFilled.compareAndSet(false, true)) {
+            Log.i(TAG, "Filling disk");
+            // initial fill done in two stage as disk can be filled by other
+            // components
+            long freeDisk = SystemUtil.getFreeDiskSize(getContext());
+            long diskToFill = freeDisk - FREE_SPACE_FINAL;
+            if (diskToFill >= 0) {
+                Log.i(TAG, "free disk " + freeDisk + ", to fill " + diskToFill);
+            } else {
+                Log.i(TAG, "free disk " + freeDisk + " too small, needs " + FREE_SPACE_FINAL);
+                return;
+            }
+            final long MAX_FILE_SIZE_TO_FILL = 1024L * 1024L * 1024L;
+            long filled = 0;
+            while (filled < diskToFill) {
+                long toFill = diskToFill - filled;
+                if (toFill > MAX_FILE_SIZE_TO_FILL) {
+                    toFill = MAX_FILE_SIZE_TO_FILL;
+                }
+                Log.i(TAG, "Generating file " + toFill);
+                FileUtil.createNewFilledFile(getContext(),
+                        DIR_INITIAL_FILL, toFill);
+                filled += toFill;
+            }
+        }
+        Log.i(TAG, "free disk " + SystemUtil.getFreeDiskSize(getContext()));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        Log.i(TAG, "tearDown free disk " + SystemUtil.getFreeDiskSize(getContext()));
+        int currentCounter = mRefCounter.decrementAndGet();
+        Log.i(TAG, "--currentCounter: " + currentCounter);
+        if (currentCounter == 0) {
+            FileUtil.removeFileOrDir(getContext(), DIR_INITIAL_FILL);
+        }
+        FileUtil.removeFileOrDir(getContext(), DIR_SEQ_UPDATE);
+        FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_WR);
+        FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_RD);
+        Log.i(TAG, "tearDown free disk " + SystemUtil.getFreeDiskSize(getContext()));
+        super.tearDown();
+    }
+
+    @TimeoutReq(minutes = 30)
+    public void testSequentialUpdate() throws Exception {
+        // now about freeSpaceToLeave should be left
+        // and try updating exceeding the free space size
+        final long FILE_SIZE = 400L * 1024L * 1024L;
+        long freeDisk = SystemUtil.getFreeDiskSize(getContext());
+        Log.i(TAG, "Now free space is " + freeDisk);
+        if (freeDisk < FILE_SIZE) {
+            Log.w(TAG, "too little space: " + freeDisk);
+            return;
+        }
+        final int BUFFER_SIZE = 10 * 1024 * 1024;
+        final int NUMBER_REPETITION = 10;
+        DeviceReportLog report = new DeviceReportLog();
+        FileUtil.doSequentialUpdateTest(getContext(), DIR_SEQ_UPDATE, report, FILE_SIZE,
+                BUFFER_SIZE, NUMBER_REPETITION);
+        report.submit(getInstrumentation());
+    }
+
+    // TODO: file size too small and caching will give wrong better result.
+    // needs to flush cache by reading big files per each read.
+    @TimeoutReq(minutes = 60)
+    public void testRandomRead() throws Exception {
+        final int BUFFER_SIZE = 4 * 1024;
+        final long fileSize = 400L * 1024L * 1024L;
+        long freeDisk = SystemUtil.getFreeDiskSize(getContext());
+        if (freeDisk < fileSize) {
+            Log.w(TAG, "too little space: " + freeDisk);
+            return;
+        }
+        DeviceReportLog report = new DeviceReportLog();
+        FileUtil.doRandomReadTest(getContext(), DIR_RANDOM_RD, report, fileSize, BUFFER_SIZE);
+        report.submit(getInstrumentation());
+    }
+
+    @TimeoutReq(minutes = 60)
+    public void testRandomUpdate() throws Exception {
+        final int BUFFER_SIZE = 4 * 1024;
+        final long fileSize = 256L * 1024L * 1024L;
+        long freeDisk = SystemUtil.getFreeDiskSize(getContext());
+        if (freeDisk < fileSize) {
+            Log.w(TAG, "too little space: " + freeDisk);
+            return;
+        }
+        DeviceReportLog report = new DeviceReportLog();
+        FileUtil.doRandomWriteTest(getContext(), DIR_RANDOM_WR, report, fileSize, BUFFER_SIZE);
+        report.submit(getInstrumentation());
+    }
+}
diff --git a/tests/filesystem/src/android/filesystem/cts/FileUtil.java b/tests/filesystem/src/android/filesystem/cts/FileUtil.java
new file mode 100755
index 0000000..baefaa0
--- /dev/null
+++ b/tests/filesystem/src/android/filesystem/cts/FileUtil.java
@@ -0,0 +1,411 @@
+/*
+ * 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 android.filesystem.cts;
+
+import android.content.Context;
+import android.cts.util.SystemUtil;
+import android.util.Log;
+
+import com.android.compatibility.common.util.MeasureRun;
+import com.android.compatibility.common.util.MeasureTime;
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.RandomAccessFile;
+import java.util.Random;
+
+public class FileUtil {
+    private static final String TAG = "FileUtil";
+    private static final Random mRandom = new Random(0);
+    private static long mFileId = 0;
+    /**
+     * create array with different data per each call
+     *
+     * @param length
+     * @param randomSeed
+     * @return
+     */
+    public static byte[] generateRandomData(int length) {
+        byte[] buffer = new byte[length];
+        int val = mRandom.nextInt();
+        for (int i = 0; i < length / 4; i++) {
+            // in little-endian
+            buffer[i * 4] = (byte)(val & 0x000000ff);
+            buffer[i * 4 + 1] = (byte)((val & 0x0000ff00) >> 8);
+            buffer[i * 4 + 2] = (byte)((val & 0x00ff0000) >> 16);
+            buffer[i * 4 + 3] = (byte)((val & 0xff000000) >> 24);
+            val++;
+        }
+        for (int i = (length / 4) * 4; i < length; i++) {
+            buffer[i] = 0;
+        }
+        return buffer;
+    }
+
+    /**
+     * create a new file under the given dirName.
+     * Existing files will not be affected.
+     * @param context
+     * @param dirName
+     * @return
+     */
+    public static File createNewFile(Context context, String dirName) {
+        File topDir = new File(context.getFilesDir(), dirName);
+        topDir.mkdir();
+        String[] list = topDir.list();
+
+        String newFileName;
+        while (true) {
+            newFileName = Long.toString(mFileId);
+            boolean fileExist = false;
+            for (String child : list) {
+                if (child.equals(newFileName)) {
+                    fileExist = true;
+                    break;
+                }
+            }
+            if (!fileExist) {
+                break;
+            }
+            mFileId++;
+        }
+        mFileId++;
+        //Log.i(TAG, "filename" + Long.toString(mFileId));
+        return new File(topDir, newFileName);
+    }
+
+    /**
+     * create multiple new files
+     * @param context
+     * @param dirName
+     * @param count number of files to create
+     * @return
+     */
+    public static File[] createNewFiles(Context context, String dirName, int count) {
+        File[] files = new File[count];
+        for (int i = 0; i < count; i++) {
+            files[i] = createNewFile(context, dirName);
+        }
+        return files;
+    }
+
+    /**
+     * write file with given byte array
+     * @param file
+     * @param data
+     * @param append will append if set true. Otherwise, write from beginning
+     * @throws IOException
+     */
+    public static void writeFile(File file, byte[] data, boolean append) throws IOException {
+        final RandomAccessFile randomFile = new RandomAccessFile(file, "rwd"); // force O_SYNC
+        if (append) {
+            randomFile.seek(randomFile.length());
+        } else {
+            randomFile.seek(0L);
+        }
+        randomFile.write(data);
+        randomFile.close();
+    }
+
+    /**
+     * create a new file with given length.
+     * @param context
+     * @param dirName
+     * @param length
+     * @return
+     * @throws IOException
+     */
+    public static File createNewFilledFile(Context context, String dirName, long length)
+            throws IOException {
+        final int BUFFER_SIZE = 10 * 1024 * 1024;
+        File file = createNewFile(context, dirName);
+        FileOutputStream out = new FileOutputStream(file);
+        byte[] data = generateRandomData(BUFFER_SIZE);
+        long written = 0;
+        while (written < length) {
+            out.write(data);
+            written += BUFFER_SIZE;
+        }
+        out.flush();
+        out.close();
+        return file;
+    }
+
+    /**
+     * remove given file or directory under the current app's files dir.
+     * @param context
+     * @param name
+     */
+    public static void removeFileOrDir(Context context, String name) {
+        File entry = new File(context.getFilesDir(), name);
+        if (entry.exists()) {
+            removeEntry(entry);
+        }
+    }
+
+    private static void removeEntry(File entry) {
+        if (entry.isDirectory()) {
+            String[] children = entry.list();
+            for (String child : children) {
+                removeEntry(new File(entry, child));
+            }
+        }
+        Log.i(TAG, "delete file " + entry.getAbsolutePath());
+        entry.delete();
+    }
+
+    /**
+     * measure time taken for each IO run with amount R/W
+     * @param count
+     * @param run
+     * @param readAmount returns amount of read in bytes for each interval.
+     *        Value will not be written if /proc/self/io does not exist.
+     * @param writeAmount returns amount of write in bytes for each interval.
+     * @return time per each interval
+     * @throws IOException
+     */
+    public static double[] measureIO(int count, double[] readAmount, double[] writeAmount,
+            MeasureRun run)  throws Exception {
+        double[] result = new double[count];
+        File procIo = new File("/proc/self/io");
+        boolean measureIo = procIo.exists() && procIo.canRead();
+        long prev = System.currentTimeMillis();
+        RWAmount prevAmount = new RWAmount();
+        if (measureIo) {
+            prevAmount = getRWAmount(procIo);
+        }
+        for (int i = 0; i < count; i++) {
+            run.run(i);
+            long current =  System.currentTimeMillis();
+            result[i] = current - prev;
+            prev = current;
+            if (measureIo) {
+                RWAmount currentAmount = getRWAmount(procIo);
+                readAmount[i] = currentAmount.mRd - prevAmount.mRd;
+                writeAmount[i] = currentAmount.mWr - prevAmount.mWr;
+                prevAmount = currentAmount;
+            }
+        }
+        return result;
+    }
+
+    private static class RWAmount {
+        public double mRd = 0.0;
+        public double mWr = 0.0;
+    };
+
+    private static RWAmount getRWAmount(File file) throws IOException {
+        RWAmount amount = new RWAmount();
+
+        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
+        String line;
+        while((line = br.readLine())!= null) {
+            if (line.startsWith("read_bytes")) {
+                amount.mRd = Double.parseDouble(line.split(" ")[1]);
+            } else if (line.startsWith("write_bytes")) {
+                amount.mWr = Double.parseDouble(line.split(" ")[1]);
+            }
+        }
+        br.close();
+        return amount;
+    }
+
+    /**
+     * get file size exceeding total memory size ( 2x total memory).
+     * The size is rounded in bufferSize. And the size will be bigger than 400MB.
+     * @param context
+     * @param bufferSize
+     * @return file size or 0 if there is not enough space.
+     */
+    public static long getFileSizeExceedingMemory(Context context, int bufferSize) {
+        long freeDisk = SystemUtil.getFreeDiskSize(context);
+        long memSize = SystemUtil.getTotalMemory(context);
+        long diskSizeTarget = (2 * memSize / bufferSize) * bufferSize;
+        final long minimumDiskSize = (512L * 1024L * 1024L / bufferSize) * bufferSize;
+        final long reservedDiskSize = (50L * 1024L * 1024L / bufferSize) * bufferSize;
+        if ( diskSizeTarget < minimumDiskSize ) {
+            diskSizeTarget = minimumDiskSize;
+        }
+        if (diskSizeTarget > freeDisk) {
+            Log.i(TAG, "Free disk size " + freeDisk + " too small");
+            return 0;
+        }
+        if ((freeDisk - diskSizeTarget) < reservedDiskSize) {
+            diskSizeTarget -= reservedDiskSize;
+        }
+        return diskSizeTarget;
+    }
+
+    /**
+     *
+     * @param context
+     * @param dirName
+     * @param report
+     * @param fileSize
+     * @param bufferSize should be power of two
+     * @throws IOException
+     */
+    public static void doRandomReadTest(Context context, String dirName, ReportLog report,
+            long fileSize, int bufferSize) throws Exception {
+        File file = FileUtil.createNewFilledFile(context,
+                dirName, fileSize);
+
+        final byte[] data = FileUtil.generateRandomData(bufferSize);
+        Random random = new Random(0);
+        final int totalReadCount = (int)(fileSize / bufferSize);
+        final int[] readOffsets = new int[totalReadCount];
+        for (int i = 0; i < totalReadCount; i++) {
+            // align in buffer size
+            readOffsets[i] = (int)(random.nextFloat() * (fileSize - bufferSize)) &
+                    ~(bufferSize - 1);
+        }
+        final int runsInOneGo = 16;
+        final int readsInOneMeasure = totalReadCount / runsInOneGo;
+
+        final RandomAccessFile randomFile = new RandomAccessFile(file, "rw"); // do not need O_SYNC
+        double[] rdAmount = new double[runsInOneGo];
+        double[] wrAmount = new double[runsInOneGo];
+        double[] times = FileUtil.measureIO(runsInOneGo, rdAmount, wrAmount, new MeasureRun() {
+
+            @Override
+            public void run(int i) throws IOException {
+                Log.i(TAG, "starting " + i + " -th round");
+                int start = i * readsInOneMeasure;
+                int end = (i + 1) * readsInOneMeasure;
+                for (int j = start; j < end; j++) {
+                    randomFile.seek(readOffsets[j]);
+                    randomFile.read(data);
+                }
+            }
+        });
+        randomFile.close();
+        double[] mbps = Stat.calcRatePerSecArray((double)fileSize / runsInOneGo / 1024 / 1024,
+                times);
+        report.addValues("read throughput",
+                mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
+        // This is just the amount of IO returned from kernel. So this is performance neutral.
+        report.addValues("read amount", rdAmount, ResultType.NEUTRAL, ResultUnit.BYTE);
+        Stat.StatResult stat = Stat.getStat(mbps);
+
+        report.setSummary("read throughput", stat.mAverage, ResultType.HIGHER_BETTER,
+                ResultUnit.MBPS);
+    }
+
+    /**
+     *
+     * @param context
+     * @param dirName
+     * @param report
+     * @param fileSize
+     * @param bufferSize should be power of two
+     * @throws IOException
+     */
+    public static void doRandomWriteTest(Context context, String dirName, ReportLog report,
+            long fileSize, int bufferSize) throws Exception {
+        File file = FileUtil.createNewFilledFile(context,
+                dirName, fileSize);
+        final byte[] data = FileUtil.generateRandomData(bufferSize);
+        Random random = new Random(0);
+        final int totalWriteCount = (int)(fileSize / bufferSize);
+        final int[] writeOffsets = new int[totalWriteCount];
+        for (int i = 0; i < totalWriteCount; i++) {
+            writeOffsets[i] = (int)(random.nextFloat() * (fileSize - bufferSize)) &
+                    ~(bufferSize - 1);
+        }
+        final int runsInOneGo = 16;
+        final int writesInOneMeasure = totalWriteCount / runsInOneGo;
+
+        final RandomAccessFile randomFile = new RandomAccessFile(file, "rwd"); // force O_SYNC
+        double[] rdAmount = new double[runsInOneGo];
+        double[] wrAmount = new double[runsInOneGo];
+        double[] times = FileUtil.measureIO(runsInOneGo, rdAmount, wrAmount, new MeasureRun() {
+
+            @Override
+            public void run(int i) throws IOException {
+                Log.i(TAG, "starting " + i + " -th round");
+                int start = i * writesInOneMeasure;
+                int end = (i + 1) * writesInOneMeasure;
+                for (int j = start; j < end; j++) {
+                    randomFile.seek(writeOffsets[j]);
+                    randomFile.write(data);
+                }
+            }
+        });
+        randomFile.close();
+        double[] mbps = Stat.calcRatePerSecArray((double)fileSize / runsInOneGo / 1024 / 1024,
+                times);
+        report.addValues("write throughput",
+                mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
+        report.addValues("write amount", wrAmount, ResultType.NEUTRAL,
+                ResultUnit.BYTE);
+        Stat.StatResult stat = Stat.getStat(mbps);
+
+        report.setSummary("write throughput", stat.mAverage, ResultType.HIGHER_BETTER,
+                ResultUnit.MBPS);
+    }
+
+    /**
+     *
+     * @param context
+     * @param dirName
+     * @param report
+     * @param fileSize fileSize should be multiple of bufferSize.
+     * @param bufferSize
+     * @param numberRepetition
+     * @throws IOException
+     */
+    public static void doSequentialUpdateTest(Context context, String dirName, ReportLog report,
+            long fileSize, int bufferSize, int numberRepetition) throws Exception {
+        File file = FileUtil.createNewFilledFile(context,
+                dirName, fileSize);
+        final byte[] data = FileUtil.generateRandomData(bufferSize);
+        int numberRepeatInOneRun = (int)(fileSize / bufferSize);
+        double[] mbpsAll = new double[numberRepetition * numberRepeatInOneRun];
+        for (int i = 0; i < numberRepetition; i++) {
+            Log.i(TAG, "starting " + i + " -th round");
+            final RandomAccessFile randomFile = new RandomAccessFile(file, "rwd");  // force O_SYNC
+            randomFile.seek(0L);
+            double[] times = MeasureTime.measure(numberRepeatInOneRun, new MeasureRun() {
+
+                @Override
+                public void run(int i) throws IOException {
+                    randomFile.write(data);
+                }
+            });
+            randomFile.close();
+            double[] mbps = Stat.calcRatePerSecArray((double)bufferSize / 1024 / 1024,
+                    times);
+            report.addValues(i + "-th round throughput",
+                    mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
+            int offset = i * numberRepeatInOneRun;
+            for (int j = 0; j < mbps.length; j++) {
+                mbpsAll[offset + j] = mbps[j];
+            }
+        }
+        Stat.StatResult stat = Stat.getStat(mbpsAll);
+        report.setSummary("update throughput", stat.mAverage, ResultType.HIGHER_BETTER,
+                ResultUnit.MBPS);
+    }
+}
diff --git a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
new file mode 100644
index 0000000..dff3723
--- /dev/null
+++ b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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 android.filesystem.cts;
+
+import android.cts.util.CtsAndroidTestCase;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.cts.util.TimeoutReq;
+
+public class RandomRWTest extends CtsAndroidTestCase {
+    private static final String DIR_RANDOM_WR = "RANDOM_WR";
+    private static final String DIR_RANDOM_RD = "RANDOM_RD";
+
+    @Override
+    protected void tearDown() throws Exception {
+        FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_WR);
+        FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_RD);
+        super.tearDown();
+    }
+
+    @TimeoutReq(minutes = 60)
+    public void testRandomRead() throws Exception {
+        final int READ_BUFFER_SIZE = 4 * 1024;
+        final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), READ_BUFFER_SIZE);
+        if (fileSize == 0) { // not enough space, give up
+            return;
+        }
+        DeviceReportLog report = new DeviceReportLog();
+        FileUtil.doRandomReadTest(getContext(), DIR_RANDOM_RD, report, fileSize,
+                READ_BUFFER_SIZE);
+        report.submit(getInstrumentation());
+    }
+
+    // It is taking too long in some device, and thus cannot run multiple times
+    @TimeoutReq(minutes = 60)
+    public void testRandomUpdate() throws Exception {
+        final int WRITE_BUFFER_SIZE = 4 * 1024;
+        final long fileSize = 256 * 1024 * 1024;
+        DeviceReportLog report = new DeviceReportLog();
+        FileUtil.doRandomWriteTest(getContext(), DIR_RANDOM_WR, report, fileSize,
+                WRITE_BUFFER_SIZE);
+        report.submit(getInstrumentation());
+    }
+}
diff --git a/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java b/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
new file mode 100644
index 0000000..3b7a45f
--- /dev/null
+++ b/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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 android.filesystem.cts;
+
+import android.cts.util.CtsAndroidTestCase;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.MeasureRun;
+import com.android.compatibility.common.util.MeasureTime;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+import com.android.cts.util.TimeoutReq;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+public class SequentialRWTest extends CtsAndroidTestCase {
+    private static final String DIR_SEQ_WR = "SEQ_WR";
+    private static final String DIR_SEQ_UPDATE = "SEQ_UPDATE";
+    private static final String DIR_SEQ_RD = "SEQ_RD";
+    private static final int BUFFER_SIZE = 10 * 1024 * 1024;
+
+    @Override
+    protected void tearDown() throws Exception {
+        FileUtil.removeFileOrDir(getContext(), DIR_SEQ_WR);
+        FileUtil.removeFileOrDir(getContext(), DIR_SEQ_UPDATE);
+        FileUtil.removeFileOrDir(getContext(), DIR_SEQ_RD);
+        super.tearDown();
+    }
+
+    @TimeoutReq(minutes = 30)
+    public void testSingleSequentialWrite() throws Exception {
+        final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), BUFFER_SIZE);
+        if (fileSize == 0) { // not enough space, give up
+            return;
+        }
+        final int numberOfFiles =(int)(fileSize / BUFFER_SIZE);
+        DeviceReportLog report = new DeviceReportLog();
+        report.addValue("files", numberOfFiles, ResultType.NEUTRAL, ResultUnit.COUNT);
+        final byte[] data = FileUtil.generateRandomData(BUFFER_SIZE);
+        final File[] files = FileUtil.createNewFiles(getContext(), DIR_SEQ_WR,
+                numberOfFiles);
+        double[] rdAmount = new double[numberOfFiles];
+        double[] wrAmount = new double[numberOfFiles];
+        double[] times = FileUtil.measureIO(numberOfFiles, rdAmount, wrAmount, new MeasureRun() {
+
+            @Override
+            public void run(int i) throws IOException {
+                FileUtil.writeFile(files[i], data, false);
+            }
+        });
+        double[] mbps = Stat.calcRatePerSecArray((double)BUFFER_SIZE / 1024 / 1024, times);
+        report.addValues("write throughput",
+                mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
+        report.addValues("write amount", wrAmount, ResultType.NEUTRAL,
+                ResultUnit.BYTE);
+        Stat.StatResult stat = Stat.getStat(mbps);
+        report.setSummary("write throughput", stat.mAverage, ResultType.HIGHER_BETTER,
+                ResultUnit.MBPS);
+        report.submit(getInstrumentation());
+    }
+
+    @TimeoutReq(minutes = 60)
+    public void testSingleSequentialUpdate() throws Exception {
+        final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), BUFFER_SIZE);
+        if (fileSize == 0) { // not enough space, give up
+            return;
+        }
+        final int NUMBER_REPETITION = 6;
+        DeviceReportLog report = new DeviceReportLog();
+        FileUtil.doSequentialUpdateTest(getContext(), DIR_SEQ_UPDATE, report, fileSize,
+                BUFFER_SIZE, NUMBER_REPETITION);
+        report.submit(getInstrumentation());
+    }
+
+    @TimeoutReq(minutes = 30)
+    public void testSingleSequentialRead() throws Exception {
+        final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), BUFFER_SIZE);
+        if (fileSize == 0) { // not enough space, give up
+            return;
+        }
+        long start = System.currentTimeMillis();
+        final File file = FileUtil.createNewFilledFile(getContext(),
+                DIR_SEQ_RD, fileSize);
+        long finish = System.currentTimeMillis();
+        DeviceReportLog report = new DeviceReportLog();
+        report.addValue("write throughput for test file of length " + fileSize,
+                Stat.calcRatePerSec((double)fileSize / 1024 / 1024, finish - start),
+                ResultType.HIGHER_BETTER, ResultUnit.MBPS);
+
+        final int NUMBER_READ = 10;
+
+        final byte[] data = new byte[BUFFER_SIZE];
+        double[] times = MeasureTime.measure(NUMBER_READ, new MeasureRun() {
+
+            @Override
+            public void run(int i) throws IOException {
+                final FileInputStream in = new FileInputStream(file);
+                long read = 0;
+                while (read < fileSize) {
+                    in.read(data);
+                    read += BUFFER_SIZE;
+                }
+                in.close();
+            }
+        });
+        double[] mbps = Stat.calcRatePerSecArray((double)fileSize / 1024 / 1024, times);
+        report.addValues("read throughput",
+                mbps, ResultType.HIGHER_BETTER, ResultUnit.MBPS);
+        Stat.StatResult stat = Stat.getStat(mbps);
+        report.setSummary("read throughput", stat.mAverage, ResultType.HIGHER_BETTER,
+                ResultUnit.MBPS);
+        report.submit(getInstrumentation());
+    }
+}
diff --git a/tests/inputmethod/Android.mk b/tests/inputmethod/Android.mk
new file mode 100644
index 0000000..6b9a6dc
--- /dev/null
+++ b/tests/inputmethod/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := CtsInputMethodTestCases
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/inputmethod/AndroidManifest.xml b/tests/inputmethod/AndroidManifest.xml
new file mode 100644
index 0000000..f283f61
--- /dev/null
+++ b/tests/inputmethod/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.cts.inputmethod">
+
+    <application >
+        <uses-library android:name="android.test.runner"/>
+
+        <activity android:name="android.inputmethod.cts.TestActivity" />
+        <service android:name="android.inputmethod.cts.MockInputMethodService"
+                 android:permission="android.permission.BIND_INPUT_METHOD">
+            <intent-filter>
+                <action android:name="android.view.InputMethod" />
+            </intent-filter>
+            <meta-data android:name="android.view.im" android:resource="@xml/method" />
+        </service>
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.inputmethod"
+                     android:label="Tests for the InputMethod APIs."/>
+
+</manifest>
diff --git a/tests/inputmethod/res/xml/method.xml b/tests/inputmethod/res/xml/method.xml
new file mode 100644
index 0000000..fc2ec95
--- /dev/null
+++ b/tests/inputmethod/res/xml/method.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+    Copyright (C) 2015 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.
+-->
+
+<input-method xmlns:android="http://schemas.android.com/apk/res/android"
+              android:isDefault="True">
+    <subtype android:imeSubtypeLocale="en_US" android:imeSubtypeMode="keyboard" />
+</input-method>
diff --git a/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTest.java b/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTest.java
new file mode 100644
index 0000000..7656cbd
--- /dev/null
+++ b/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2015 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.inputmethod.cts;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.inputmethodservice.InputMethodService;
+import android.test.InstrumentationTestCase;
+import android.view.inputmethod.InputMethodManager;
+
+import java.util.List;
+
+public class InputMethodServiceTest extends InstrumentationTestCase {
+    private String mTestImeId;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mTestImeId = getInstrumentation().getContext().getPackageName() +
+                "/" + MockInputMethodService.class.getName();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Ensures that the IME with {@code imeId} is not enabled.
+     *
+     * This method ensures that no IME with {@code imeId} is enabled. If the given IME is currently
+     * in use, switches to another IME first. Then, if the given IME is enabled, disables it.
+     */
+    private void ensureImeNotEnabled(@NonNull final String imeId) {
+        final String currentImeId =
+                InputMethodServiceTestUtil.getCurrentImeId(getInstrumentation());
+        if (currentImeId.equals(imeId)) {
+            // Requested IME is already used. This typically happens if the previous test case is
+            // not finished gracefully. In this case, selects another IME.
+            String otherImeCandidate = null;
+            final List<String> enabledImes =
+                    InputMethodServiceTestUtil.getEnabledImeIds(getInstrumentation());
+            for (final String enabledIme : enabledImes) {
+                if (!enabledIme.equals(imeId)) {
+                    otherImeCandidate = imeId;
+                    break;
+                }
+            }
+            if (otherImeCandidate == null) {
+                // When PackageManager.hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)
+                // returns true, this case must not happen.
+                throw new IllegalStateException(
+                        "No other IME is available. Unable to continue tests.");
+            }
+            assertTrue(InputMethodServiceTestUtil.setIme(getInstrumentation(), otherImeCandidate));
+        }
+
+        if (InputMethodServiceTestUtil.isImeEnabled(getInstrumentation(), imeId)) {
+            assertTrue(InputMethodServiceTestUtil.disableIme(getInstrumentation(), imeId));
+        }
+    }
+
+    /**
+     * Asserts the given service is not running.
+     */
+    private void assertServiceNotRunning() {
+        assertTrue(MockInputMethodService.getInstance() == null ||
+                MockInputMethodService.getInstance().getCallCount("onCreate") == 0);
+    }
+
+    /**
+     * This test checks the following APIs.
+     * <ul>
+     *   <li>{@link InputMethodManager#getEnabledInputMethodList()}</li>
+     *   <li>{@link InputMethodManager#getInputMethodList()}</li>
+     *   <li>{@link InputMethodManager#setInputMethod(IBinder, String)}</li>
+     *   <li>{@link InputMethodService#onCreate()}</li>
+     *   <li>{@link InputMethodService#onDestroy()}</li>
+     * </ul>
+     */
+    public void testCreateAndDestroy() {
+        if (!getInstrumentation().getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_INPUT_METHODS)) {
+            // The "input method" system feature is not supported on this device.
+            return;
+        }
+
+        // Clear the counter in the mock service, since it might have been used in a previous test.
+        MockInputMethodService.resetCounter();
+
+        ensureImeNotEnabled(mTestImeId);
+
+        final String ImeIdToRestore =
+                InputMethodServiceTestUtil.getCurrentImeId(getInstrumentation());
+        MockInputMethodService service = MockInputMethodService.getInstance();
+        assertServiceNotRunning();
+
+        try {
+            // Enable test IME.
+            assertTrue(InputMethodServiceTestUtil.enableIme(getInstrumentation(), mTestImeId));
+            service = MockInputMethodService.getInstance();
+            assertServiceNotRunning();
+
+            // Select test IME.
+            assertTrue(InputMethodServiceTestUtil.setIme(getInstrumentation(), mTestImeId));
+            service = MockInputMethodService.getInstance();
+            assertNotNull(service);
+            assertEquals(1, MockInputMethodService.getCallCount("<init>"));
+            assertEquals(1, MockInputMethodService.getCallCount("onCreate"));
+        } finally {
+            // Restores IMEs to original one.
+            InputMethodServiceTestUtil.setIme(getInstrumentation(), ImeIdToRestore);
+            InputMethodServiceTestUtil.disableIme(getInstrumentation(), mTestImeId);
+            assertEquals(1, MockInputMethodService.getCallCount("onDestroy"));
+        }
+    }
+}
diff --git a/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTestUtil.java b/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTestUtil.java
new file mode 100644
index 0000000..aa46c38
--- /dev/null
+++ b/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTestUtil.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2015 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.inputmethod.cts;
+
+import android.annotation.NonNull;
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility functions for testing of input method stuff.
+ */
+public final class InputMethodServiceTestUtil {
+    private static final String TAG = InputMethodServiceTestUtil.class.getSimpleName();
+
+    // Prevents this from being instantiated.
+    private InputMethodServiceTestUtil() {}
+
+    @NonNull
+    private static String executeShellCommand(final UiAutomation uiAutomation, final String[] cmd) {
+        final String flattenCmd = TextUtils.join(" ", cmd);
+        List<String> output = new ArrayList<>();
+
+        try (final ParcelFileDescriptor fd = uiAutomation.executeShellCommand(flattenCmd);
+             final FileReader fr = new FileReader(fd.getFileDescriptor());
+             final BufferedReader br = new BufferedReader(fr)) {
+
+            String line;
+            while ((line = br.readLine()) != null) {
+                output.add(line);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        // The output from the "ime" command should be only one line.
+        if (output.size() != 1) {
+            throw new IllegalStateException(
+                    "The output from 'ime' command should be one line, but it outputs multiples: " +
+                    TextUtils.join("\n", output));
+        }
+        return output.get(0);
+    }
+
+    @NonNull
+    public static String getCurrentImeId(final Instrumentation inst) {
+        return Settings.Secure.getString(inst.getContext().getContentResolver(),
+                Settings.Secure.DEFAULT_INPUT_METHOD);
+    }
+
+    public static boolean isImeEnabled(final Instrumentation inst, final String imeId) {
+        final List<String> enabledImes = getEnabledImeIds(inst);
+        return enabledImes.contains(imeId);
+    }
+
+    @NonNull
+    public static List<String> getEnabledImeIds(final Instrumentation inst) {
+        InputMethodManager imm = (InputMethodManager) inst.getContext().getSystemService(
+                Context.INPUT_METHOD_SERVICE);
+        final List<InputMethodInfo> enabledImes = imm.getEnabledInputMethodList();
+        List<String> result = new ArrayList<>();
+        for (final InputMethodInfo enabledIme : enabledImes) {
+            result.add(enabledIme.getId());
+        }
+        return result;
+    }
+
+    /**
+     * Puts the specified IME into the available input method list.
+     *
+     * This operation will be done synchronously in "ime" command using
+     * {@link com.android.server.InputMethodManagerService#setInputMethodEnabled(String, boolean)},
+     * which is synchronous.
+     *
+     * @param imeId IME ID to be enabled.
+     * @return {@code true} if the target IME gets enabled successfully. {@code false} if failed.
+     */
+    public static boolean enableIme(final Instrumentation inst, final String imeId) {
+        // Needs to check the output message from the checking command, since executeShellCommand()
+        // does not pass the exit status code back to the test.
+        final String output = executeShellCommand(
+                inst.getUiAutomation(), new String[]{"ime", "enable", imeId});
+        final String expectedOutput = "Input method " + imeId + ": now enabled";
+        if (!output.equals(expectedOutput)) {
+            Log.e(TAG, "Unexpected output message. Expected: " + expectedOutput +
+                    ", Actual: " + output);
+            return false;
+        }
+
+        final InputMethodManager imm = (InputMethodManager) inst.getContext().getSystemService(
+                Context.INPUT_METHOD_SERVICE);
+        final List<InputMethodInfo> enabledInputMethods = imm.getEnabledInputMethodList();
+        for (final InputMethodInfo imi : enabledInputMethods) {
+            if (imi.getId().equals(imeId))
+                return true;
+        }
+
+        Log.e(TAG, "Failed to enable the given IME (IME ID: " + imeId + ").");
+        return false;
+    }
+
+    /**
+     * Removes the specified IME from the available input method list.
+     *
+     * This operation will {@code @NonNull} final be done synchronously in "ime" command using
+     * {@link com.android.server.InputMethodManagerService#setInputMethodEnabled(String, boolean)},
+     * which is synchronous.
+     *
+     * @param imeId IME ID to be disabled.
+     * @return {@code true} if the target IME gets disabled successfully. {@code false} if failed.
+     */
+    public static boolean disableIme(final Instrumentation inst, final String imeId) {
+        // Needs to check the output message from the checking command, since executeShellCommand()
+        // does not pass the exit status code back to the test.
+        final String output = executeShellCommand(
+                inst.getUiAutomation(), new String[]{"ime", "disable", imeId});
+        final String expectedOutput = "Input method " + imeId + ": now disabled";
+        if (!output.equals(expectedOutput)) {
+            Log.w(TAG, "Unexpected output message. Expected: " + expectedOutput +
+                    ", Actual: " + output);
+            return false;
+        }
+
+        final InputMethodManager imm = (InputMethodManager) inst.getContext().getSystemService(
+                Context.INPUT_METHOD_SERVICE);
+        final List<InputMethodInfo> enabledInputMethods = imm.getEnabledInputMethodList();
+        for (final InputMethodInfo imi : enabledInputMethods) {
+            if (imi.getId().equals(imeId)) {
+                Log.e(TAG, "Failed to disable the given IME (IME ID: " + imeId + ").");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Switches to the specified IME.
+     *
+     * This operation will be done synchronously in the "ime" command using
+     * {@link InputMethodManager#setInputMethod(IBinder, String)}, which is synchronous.
+     *
+     * @param imeId IME ID to be switched to.
+     * @return {@code true} if the target IME gets active successfully. {@code false} if failed.
+     */
+    public static boolean setIme(final Instrumentation inst, final String imeId) {
+        // Needs to check the output message from the checking command, since executeShellCommand()
+        // does not pass the exit status code back to the test.
+        final String output = executeShellCommand(
+                inst.getUiAutomation(), new String[]{"ime", "set", imeId});
+        final String expectedOutput = "Input method " + imeId + " selected";
+        if (!output.equals(expectedOutput)) {
+            Log.w(TAG, "Unexpected output message. Expected: " + expectedOutput +  ", Actual: " +
+                    output);
+            return false;
+        }
+
+        final String currentImeId = getCurrentImeId(inst);
+        if (!TextUtils.equals(currentImeId, imeId)) {
+            Log.e(TAG, "Failed to switch the current IME. Expected: " + imeId +  ", Actual: " +
+                    currentImeId);
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/tests/inputmethod/src/android/inputmethod/cts/MockInputMethodService.java b/tests/inputmethod/src/android/inputmethod/cts/MockInputMethodService.java
new file mode 100644
index 0000000..12b80a5
--- /dev/null
+++ b/tests/inputmethod/src/android/inputmethod/cts/MockInputMethodService.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 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.inputmethod.cts;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.inputmethodservice.InputMethodService;
+
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * A mock implementation of {@link InputMethodService} for testing purpose.
+ */
+public class MockInputMethodService extends InputMethodService {
+    private static AtomicReference<MockInputMethodService> sCurrentInstance =
+            new AtomicReference<>();
+    private static final HashMap<String, Integer> mCallCounter = new HashMap<>();
+
+    /**
+     * @return The instance of {@code MockInputMethodService}. If the service has not been created
+     * yet or already been destroyed, returns {@code null}.
+     */
+    @Nullable
+    public static MockInputMethodService getInstance() {
+        return sCurrentInstance.get();
+    }
+
+    public static void resetCounter() {
+        synchronized (mCallCounter) {
+            mCallCounter.clear();
+        }
+    }
+
+    private static void incrementCallCount(@NonNull final String methodName) {
+        synchronized (mCallCounter) {
+            if (!mCallCounter.containsKey(methodName)) {
+                mCallCounter.put(methodName, 0);
+            }
+            mCallCounter.put(methodName, mCallCounter.get(methodName) + 1);
+        }
+    }
+
+    public static int getCallCount(@NonNull final String methodName) {
+        synchronized (mCallCounter) {
+            if (!mCallCounter.containsKey(methodName)) {
+                return 0;
+            }
+            return mCallCounter.get(methodName);
+        }
+    }
+
+    public MockInputMethodService() {
+        incrementCallCount("<init>");
+    }
+
+    @Override
+    public void onCreate() {
+        if (!sCurrentInstance.compareAndSet(null, this)) {
+            throw new IllegalStateException("New MockInputMethodService instance is being created "
+                    + "before the existing instance is destroyed.");
+        }
+
+        super.onCreate();
+        incrementCallCount("onCreate");
+    }
+
+    @Override
+    public void onDestroy() {
+        sCurrentInstance.lazySet(null);
+        super.onDestroy();
+        incrementCallCount("onDestroy");
+    }
+}
+
diff --git a/tests/jank/Android.mk b/tests/jank/Android.mk
new file mode 100644
index 0000000..46db307
--- /dev/null
+++ b/tests/jank/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsJankDeviceTestCases
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner ub-uiautomator ub-janktesthelper
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/jank/AndroidManifest.xml b/tests/jank/AndroidManifest.xml
new file mode 100644
index 0000000..cbb4cba
--- /dev/null
+++ b/tests/jank/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.jank.cts">
+
+  <application>
+      <uses-library android:name="android.test.runner"/>
+  </application>
+
+  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                   android:targetPackage="android.jank.cts"
+                   android:label="Jank tests">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/jank/AndroidTest.xml b/tests/jank/AndroidTest.xml
new file mode 100644
index 0000000..c7e476a
--- /dev/null
+++ b/tests/jank/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Jank test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsUiDeviceTestCases.apk" />
+        <option name="test-file-name" value="CtsJankDeviceTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.jank.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/jank/OldAndroidTest.xml b/tests/jank/OldAndroidTest.xml
new file mode 100644
index 0000000..633f650
--- /dev/null
+++ b/tests/jank/OldAndroidTest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Jank Test Cases">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsUiDeviceTestCases.apk" />
+</configuration>
diff --git a/tests/jank/src/android/jank/cts/CtsJankTestBase.java b/tests/jank/src/android/jank/cts/CtsJankTestBase.java
new file mode 100644
index 0000000..fb2f867
--- /dev/null
+++ b/tests/jank/src/android/jank/cts/CtsJankTestBase.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 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.jank.cts;
+
+import android.os.Bundle;
+import android.support.test.jank.JankTestBase;
+import android.support.test.jank.WindowContentFrameStatsMonitor;
+import android.support.test.uiautomator.UiDevice;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+public abstract class CtsJankTestBase extends JankTestBase {
+
+    private UiDevice mDevice;
+    private DeviceReportLog mLog;
+
+    @Override
+    public void afterTest(Bundle metrics) {
+        String source = String.format("%s#%s", getClass().getCanonicalName(), getName());
+        mLog.addValue(source, WindowContentFrameStatsMonitor.KEY_AVG_FPS,
+                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_FPS),
+                ResultType.HIGHER_BETTER, ResultUnit.FPS);
+        mLog.addValue(source, WindowContentFrameStatsMonitor.KEY_AVG_LONGEST_FRAME,
+                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_LONGEST_FRAME),
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        mLog.addValue(source, WindowContentFrameStatsMonitor.KEY_MAX_NUM_JANKY,
+                metrics.getInt(WindowContentFrameStatsMonitor.KEY_MAX_NUM_JANKY),
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        mLog.setSummary(WindowContentFrameStatsMonitor.KEY_AVG_NUM_JANKY,
+                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_NUM_JANKY),
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mLog = new DeviceReportLog();
+        // fix device orientation
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        mDevice.setOrientationNatural();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mLog.submit(getInstrumentation());
+        // restore device orientation
+        mDevice.unfreezeRotation();
+        super.tearDown();
+    }
+
+    protected UiDevice getUiDevice() {
+        return mDevice;
+    }
+}
diff --git a/tests/jank/src/android/jank/cts/ui/CtsDeviceJankUi.java b/tests/jank/src/android/jank/cts/ui/CtsDeviceJankUi.java
new file mode 100644
index 0000000..2e389d7
--- /dev/null
+++ b/tests/jank/src/android/jank/cts/ui/CtsDeviceJankUi.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 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.jank.cts.ui;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.jank.cts.CtsJankTestBase;
+import android.os.SystemClock;
+import android.support.test.jank.JankTest;
+import android.support.test.jank.WindowContentFrameStatsMonitor;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.Until;
+import android.widget.ListView;
+
+import java.io.IOException;
+
+public class CtsDeviceJankUi extends CtsJankTestBase {
+    private final static int NUM_ELEMENTS = 1000;
+    private static final long DEFAULT_ANIMATION_TIME = 2 * 1000;
+    private static final long POST_SCROLL_IDLE_TIME = 2 *1000;
+    private final static String PACKAGE = "android.ui.cts";
+    private final static String CLASS = PACKAGE + ".ScrollingActivity";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // launch the activity as part of the set up
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setComponent(new ComponentName(PACKAGE, CLASS));
+        intent.putExtra("num_elements", NUM_ELEMENTS);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        getInstrumentation().getTargetContext().startActivity(intent);
+        getUiDevice().wait(Until.hasObject(By.pkg(PACKAGE)), DEFAULT_ANIMATION_TIME);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        getUiDevice().pressHome();
+        super.tearDown();
+    }
+
+    @JankTest(expectedFrames=50, defaultIterationCount=5)
+    @WindowContentFrameStatsMonitor
+    public void testScrolling() throws IOException {
+        getUiDevice().findObject(By.clazz(ListView.class)).fling(Direction.DOWN);
+        SystemClock.sleep(POST_SCROLL_IDLE_TIME);
+    }
+}
diff --git a/tests/leanbackjank/Android.mk b/tests/leanbackjank/Android.mk
index b3adfb1..45d194f 100644
--- a/tests/leanbackjank/Android.mk
+++ b/tests/leanbackjank/Android.mk
@@ -21,11 +21,22 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-        ./app/src/android/cts/jank/leanback/IntentKeys.java
+        ./app/src/android/leanbackjank/app/IntentKeys.java
 
 LOCAL_PACKAGE_NAME := CtsLeanbackJankTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ub-uiautomator ub-janktesthelper android-support-v17-leanback
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ctsdeviceutil \
+    ctstestrunner \
+    ub-uiautomator \
+    ub-janktesthelper \
+    android-support-v17-leanback \
+    android-support-v4
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/leanbackjank/AndroidManifest.xml b/tests/leanbackjank/AndroidManifest.xml
index 1cd552d..27cdbe6 100644
--- a/tests/leanbackjank/AndroidManifest.xml
+++ b/tests/leanbackjank/AndroidManifest.xml
@@ -17,15 +17,15 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="android.cts.leanbackjank">
+        package="android.leanbackjank.cts">
 
   <application>
       <uses-library android:name="android.test.runner"/>
   </application>
 
   <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                   android:targetPackage="android.cts.leanbackjank"
-                   android:label="Jank tests">
+                   android:targetPackage="android.leanbackjank.cts"
+                   android:label="LeanbackJank tests">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/leanbackjank/AndroidTest.xml b/tests/leanbackjank/AndroidTest.xml
index e61c58d..a07c2eb 100644
--- a/tests/leanbackjank/AndroidTest.xml
+++ b/tests/leanbackjank/AndroidTest.xml
@@ -13,7 +13,13 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="CTS Jank test config">
-    <include name="common-config" />
-    <option name="cts-apk-installer:test-file-name" value="CtsLeanbackJank.apk" />
+<configuration description="Config for CTS LeanbackJank test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsLeanbackJankTestCases.apk" />
+        <option name="test-file-name" value="CtsLeanbackJankApp.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.leanbackjank.cts" />
+    </test>
 </configuration>
diff --git a/tests/leanbackjank/OldAndroidTest.xml b/tests/leanbackjank/OldAndroidTest.xml
new file mode 100644
index 0000000..1ee5722
--- /dev/null
+++ b/tests/leanbackjank/OldAndroidTest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS LeanbackJank Test Cases">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsLeanbackJankApp.apk" />
+</configuration>
diff --git a/tests/leanbackjank/app/Android.mk b/tests/leanbackjank/app/Android.mk
index 5abe1a7..c2bab35 100644
--- a/tests/leanbackjank/app/Android.mk
+++ b/tests/leanbackjank/app/Android.mk
@@ -22,7 +22,10 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := CtsLeanbackJank
+LOCAL_PACKAGE_NAME := CtsLeanbackJankApp
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 LOCAL_RESOURCE_DIR := \
     $(TOP)/frameworks/support/v17/leanback/res \
diff --git a/tests/leanbackjank/app/AndroidManifest.xml b/tests/leanbackjank/app/AndroidManifest.xml
index 333399e..1e1ff3b 100644
--- a/tests/leanbackjank/app/AndroidManifest.xml
+++ b/tests/leanbackjank/app/AndroidManifest.xml
@@ -16,7 +16,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.cts.jank.leanback"
+    package="android.leanbackjank.app"
     android:versionCode="1"
     android:versionName="1.1" >
 
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/IntentKeys.java b/tests/leanbackjank/app/src/android/cts/jank/leanback/IntentKeys.java
deleted file mode 100644
index e9c5e6e..0000000
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/IntentKeys.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package android.cts.jank.leanback;
-
-/**
- * Intent key strings of the leanback jank test helper app.
- */
-public class IntentKeys {
-    public static final String SCROLL_COUNT = "SCROLL_COUNT";
-    public static final String SCROLL_DELAY = "SCROLL_DELAY";
-    public static final String SCROLL_INTERVAL = "SCROLL_INTERVAL";
-}
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/Utils.java b/tests/leanbackjank/app/src/android/cts/jank/leanback/Utils.java
deleted file mode 100644
index de6d6af..0000000
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/Utils.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.jank.leanback;
-
-import android.app.Activity;
-import android.content.Context;
-import android.graphics.Point;
-import android.media.MediaMetadataRetriever;
-import android.os.Build;
-import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.Toast;
-import android.widget.VideoView;
-
-import java.util.HashMap;
-
-/**
- * A collection of utility methods, all static.
- */
-public class Utils {
-
-    public interface MediaDimensions {
-        double MEDIA_HEIGHT = 0.95;
-        double MEDIA_WIDTH = 0.95;
-        double MEDIA_TOP_MARGIN = 0.025;
-        double MEDIA_RIGHT_MARGIN = 0.025;
-        double MEDIA_BOTTOM_MARGIN = 0.025;
-        double MEDIA_LEFT_MARGIN = 0.025;
-    }
-
-    /*
-     * Making sure public utility methods remain static
-     */
-    private Utils() {
-    }
-
-    /**
-     * Returns the screen/display size
-     */
-    public static Point getDisplaySize(Context context) {
-        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        Display display = wm.getDefaultDisplay();
-        Point size = new Point();
-        display.getSize(size);
-        return size;
-    }
-
-    /**
-     * Shows a (long) toast
-     */
-    public static void showToast(Context context, String msg) {
-        Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
-    }
-
-    /**
-     * Shows a (long) toast.
-     */
-    public static void showToast(Context context, int resourceId) {
-        Toast.makeText(context, context.getString(resourceId), Toast.LENGTH_LONG).show();
-    }
-
-    public static int convertDpToPixel(Context ctx, int dp) {
-        float density = ctx.getResources().getDisplayMetrics().density;
-        return Math.round((float) dp * density);
-    }
-
-
-    /**
-     * Example for handling resizing content for overscan.  Typically you won't need to resize
-     * when using the Leanback support library.
-     */
-    public void overScan(Activity activity, VideoView videoView) {
-        DisplayMetrics metrics = new DisplayMetrics();
-        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
-        int w = (int) (metrics.widthPixels * MediaDimensions.MEDIA_WIDTH);
-        int h = (int) (metrics.heightPixels * MediaDimensions.MEDIA_HEIGHT);
-        int marginLeft = (int) (metrics.widthPixels * MediaDimensions.MEDIA_LEFT_MARGIN);
-        int marginTop = (int) (metrics.heightPixels * MediaDimensions.MEDIA_TOP_MARGIN);
-        int marginRight = (int) (metrics.widthPixels * MediaDimensions.MEDIA_RIGHT_MARGIN);
-        int marginBottom = (int) (metrics.heightPixels * MediaDimensions.MEDIA_BOTTOM_MARGIN);
-        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(w, h);
-        lp.setMargins(marginLeft, marginTop, marginRight, marginBottom);
-        videoView.setLayoutParams(lp);
-    }
-
-
-    public static long getDuration(String videoUrl) {
-        MediaMetadataRetriever mmr = new MediaMetadataRetriever();
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-            mmr.setDataSource(videoUrl, new HashMap<String, String>());
-        } else {
-            mmr.setDataSource(videoUrl);
-        }
-        return Long.parseLong(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
-    }
-}
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/data/VideoProvider.java b/tests/leanbackjank/app/src/android/cts/jank/leanback/data/VideoProvider.java
deleted file mode 100644
index fa317ed..0000000
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/data/VideoProvider.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.jank.leanback.data;
-
-import android.cts.jank.leanback.model.Movie;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Provides synthesized movie data.
- */
-public class VideoProvider {
-    private static HashMap<String, List<Movie>> sMovieList;
-    private static HashMap<String, Movie> sMovieListById;
-
-    public static Movie getMovieById(String mediaId) {
-        return sMovieListById.get(mediaId);
-    }
-
-    public static HashMap<String, List<Movie>> getMovieList() {
-        return sMovieList;
-    }
-
-    public static HashMap<String, List<Movie>> buildMedia(int nCategories) {
-        if (null != sMovieList) {
-            return sMovieList;
-        }
-        sMovieList = new HashMap<>();
-        sMovieListById = new HashMap<>();
-
-        String title = new String();
-        String studio = new String();
-        for (int i = 0; i < nCategories; i++) {
-            String category_name = String.format("Category %d",  i);
-            List<Movie> categoryList = new ArrayList<Movie>();
-            for (int j = 0; j < 20; j++) {
-                String description = "This is description of a movie.";
-                title = String.format("Video %d-%d", i, j);
-                studio = String.format("Studio %d", (i + j) % 7);
-                Movie movie = buildMovieInfo(category_name, title, description, studio);
-                sMovieListById.put(movie.getId(), movie);
-                categoryList.add(movie);
-            }
-            sMovieList.put(category_name, categoryList);
-        }
-        return sMovieList;
-    }
-
-    private static Movie buildMovieInfo(String category,
-                                        String title,
-                                        String description,
-                                        String studio) {
-        Movie movie = new Movie();
-        movie.setId(Movie.getCount());
-        Movie.incrementCount();
-        movie.setTitle(title);
-        movie.setDescription(description);
-        movie.setStudio(studio);
-        movie.setCategory(category);
-
-        return movie;
-    }
-}
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/model/Movie.java b/tests/leanbackjank/app/src/android/cts/jank/leanback/model/Movie.java
deleted file mode 100644
index 874bb00..0000000
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/model/Movie.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.jank.leanback.model;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Movie class represents video entity with title, description, image thumbs and video url.
- */
-public class Movie implements Parcelable {
-    static final long serialVersionUID = 727566175075960653L;
-    private static int sCount = 0;
-    private String mId;
-    private String mTitle;
-    private String mDescription;
-    private String mStudio;
-    private String mCategory;
-
-    public Movie() {
-    }
-
-    public Movie(Parcel in){
-        String[] data = new String[5];
-
-        in.readStringArray(data);
-        mId = data[0];
-        mTitle = data[1];
-        mDescription = data[2];
-        mStudio = data[3];
-        mCategory = data[4];
-    }
-
-    public static String getCount() {
-        return Integer.toString(sCount);
-    }
-
-    public static void incrementCount() {
-        sCount++;
-    }
-
-    public String getId() {
-        return mId;
-    }
-
-    public void setId(String id) {
-        mId = id;
-    }
-
-    public String getTitle() {
-        return mTitle;
-    }
-
-    public void setTitle(String title) {
-        mTitle = title;
-    }
-
-    public String getDescription() {
-        return mDescription;
-    }
-
-    public void setDescription(String description) {
-        mDescription = description;
-    }
-
-    public String getStudio() {
-        return mStudio;
-    }
-
-    public void setStudio(String studio) {
-        mStudio = studio;
-    }
-
-    public String getCategory() {
-        return mCategory;
-    }
-
-    public void setCategory(String category) {
-        mCategory = category;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStringArray(new String[] {mId,
-                mTitle,
-                mDescription,
-                mStudio,
-                mCategory});
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder(200);
-        sb.append("Movie{");
-        sb.append("mId=" + mId);
-        sb.append(", mTitle='" + mTitle + '\'');
-        sb.append('}');
-        return sb.toString();
-    }
-
-    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
-        public Movie createFromParcel(Parcel in) {
-            return new Movie(in);
-        }
-
-        public Movie[] newArray(int size) {
-            return new Movie[size];
-        }
-    };
-}
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/CardPresenter.java b/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/CardPresenter.java
deleted file mode 100644
index 9f425ca..0000000
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/CardPresenter.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.jank.leanback.presenter;
-
-import android.graphics.drawable.Drawable;
-import android.support.v17.leanback.widget.ImageCardView;
-import android.support.v17.leanback.widget.Presenter;
-import android.view.ViewGroup;
-
-import com.bumptech.glide.Glide;
-import android.cts.jank.leanback.R;
-import android.cts.jank.leanback.model.Movie;
-
-/**
- * A CardPresenter is used to generate Views and bind Objects to them on demand.
- * It contains an Image CardView
- */
-public class CardPresenter extends Presenter {
-    private static int CARD_WIDTH = 313;
-    private static int CARD_HEIGHT = 176;
-    private static int sSelectedBackgroundColor;
-    private static int sDefaultBackgroundColor;
-    private Drawable mDefaultCardImage;
-
-    @Override
-    public ViewHolder onCreateViewHolder(ViewGroup parent) {
-        sDefaultBackgroundColor = parent.getResources().getColor(R.color.default_background, null);
-        sSelectedBackgroundColor =
-                parent.getResources().getColor(R.color.selected_background, null);
-        mDefaultCardImage = parent.getResources().getDrawable(R.drawable.movie, null);
-
-        ImageCardView cardView = new ImageCardView(parent.getContext()) {
-            @Override
-            public void setSelected(boolean selected) {
-                updateCardBackgroundColor(this, selected);
-                super.setSelected(selected);
-            }
-        };
-
-        cardView.setFocusable(true);
-        cardView.setFocusableInTouchMode(true);
-        updateCardBackgroundColor(cardView, false);
-        return new ViewHolder(cardView);
-    }
-
-    private static void updateCardBackgroundColor(ImageCardView view, boolean selected) {
-        int color = selected ? sSelectedBackgroundColor : sDefaultBackgroundColor;
-        // Both background colors should be set because the view's background is temporarily visible
-        // during animations.
-        view.setBackgroundColor(color);
-        view.findViewById(R.id.info_field).setBackgroundColor(color);
-    }
-
-    @Override
-    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
-        Movie movie = (Movie) item;
-        ImageCardView cardView = (ImageCardView) viewHolder.view;
-
-        cardView.setTitleText(movie.getTitle());
-        cardView.setContentText(movie.getStudio());
-        cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT);
-        Glide.with(viewHolder.view.getContext())
-                .load(R.drawable.gradation)
-                .centerCrop()
-                .error(mDefaultCardImage)
-                .into(cardView.getMainImageView());
-    }
-
-    @Override
-    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
-        ImageCardView cardView = (ImageCardView) viewHolder.view;
-        // Remove references to images so that the garbage collector can free up memory
-        cardView.setBadgeImage(null);
-        cardView.setMainImage(null);
-    }
-}
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/GridItemPresenter.java b/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/GridItemPresenter.java
deleted file mode 100644
index 4084383..0000000
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/GridItemPresenter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.jank.leanback.presenter;
-
-import android.graphics.Color;
-import android.support.v17.leanback.widget.Presenter;
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import android.cts.jank.leanback.R;
-import android.cts.jank.leanback.ui.MainFragment;
-
-public class GridItemPresenter extends Presenter {
-    private static int GRID_ITEM_WIDTH = 200;
-    private static int GRID_ITEM_HEIGHT = 200;
-
-    private MainFragment mainFragment;
-
-    public GridItemPresenter(MainFragment mainFragment) {
-        this.mainFragment = mainFragment;
-    }
-
-    @Override
-    public ViewHolder onCreateViewHolder(ViewGroup parent) {
-        TextView view = new TextView(parent.getContext());
-        view.setLayoutParams(new ViewGroup.LayoutParams(GRID_ITEM_WIDTH, GRID_ITEM_HEIGHT));
-        view.setFocusable(true);
-        view.setFocusableInTouchMode(true);
-        view.setBackgroundColor(
-            mainFragment.getResources().getColor(R.color.default_background, null));
-        view.setTextColor(Color.WHITE);
-        view.setGravity(Gravity.CENTER);
-        return new ViewHolder(view);
-    }
-
-    @Override
-    public void onBindViewHolder(ViewHolder viewHolder, Object item) {
-        ((TextView) viewHolder.view).setText((String) item);
-    }
-
-    @Override
-    public void onUnbindViewHolder(ViewHolder viewHolder) {
-    }
-}
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/IconHeaderItemPresenter.java b/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/IconHeaderItemPresenter.java
deleted file mode 100644
index 42e4c0c..0000000
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/IconHeaderItemPresenter.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.jank.leanback.presenter;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.support.v17.leanback.widget.HeaderItem;
-import android.support.v17.leanback.widget.ListRow;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.RowHeaderPresenter;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import android.cts.jank.leanback.R;
-
-public class IconHeaderItemPresenter extends RowHeaderPresenter {
-    private float mUnselectedAlpha;
-
-    @Override
-    public ViewHolder onCreateViewHolder(ViewGroup viewGroup) {
-        mUnselectedAlpha = viewGroup.getResources()
-                .getFraction(R.fraction.lb_browse_header_unselect_alpha, 1, 1);
-        LayoutInflater inflater = (LayoutInflater) viewGroup.getContext()
-                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
-        View view = inflater.inflate(R.layout.icon_header_item, null);
-
-        return new ViewHolder(view);
-    }
-
-    @Override
-    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object o) {
-        HeaderItem headerItem = ((ListRow) o).getHeaderItem();
-        View rootView = viewHolder.view;
-
-        ImageView iconView = (ImageView) rootView.findViewById(R.id.header_icon);
-        Drawable icon = rootView.getResources().getDrawable(R.drawable.android_header, null);
-        iconView.setImageDrawable(icon);
-
-        TextView label = (TextView) rootView.findViewById(R.id.header_label);
-        label.setText(headerItem.getName());
-    }
-
-    @Override
-    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
-    }
-
-    // TODO: TEMP - remove me when leanback onCreateViewHolder no longer sets the mUnselectAlpha,AND
-    // also assumes the xml inflation will return a RowHeaderView
-    @Override
-    protected void onSelectLevelChanged(RowHeaderPresenter.ViewHolder holder) {
-        // this is a temporary fix
-        holder.view.setAlpha(mUnselectedAlpha + holder.getSelectLevel() *
-                (1.0f - mUnselectedAlpha));
-    }
-}
\ No newline at end of file
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainActivity.java b/tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainActivity.java
deleted file mode 100644
index fb27fa1..0000000
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainActivity.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.jank.leanback.ui;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.cts.jank.leanback.R;
-
-/**
- * MainActivity class that loads MainFragment
- */
-public class MainActivity extends Activity {
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-    }
-
-    @Override
-    public boolean onSearchRequested() {
-        return false;
-    }
-}
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainFragment.java b/tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainFragment.java
deleted file mode 100644
index e645f6b..0000000
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainFragment.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.jank.leanback.ui;
-
-import android.content.Intent;
-import android.content.res.Resources.Theme;
-import android.cts.jank.leanback.IntentKeys;
-import android.cts.jank.leanback.R;
-import android.cts.jank.leanback.data.VideoProvider;
-import android.cts.jank.leanback.model.Movie;
-import android.cts.jank.leanback.presenter.CardPresenter;
-import android.cts.jank.leanback.presenter.GridItemPresenter;
-import android.cts.jank.leanback.presenter.IconHeaderItemPresenter;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v17.leanback.app.BackgroundManager;
-import android.support.v17.leanback.app.BrowseFragment;
-import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.HeaderItem;
-import android.support.v17.leanback.widget.ListRow;
-import android.support.v17.leanback.widget.ListRowPresenter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.util.DisplayMetrics;
-import android.view.View;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
-
-/**
- * Main class to show BrowseFragment with header and rows of videos
- */
-public class MainFragment extends BrowseFragment {
-    private static final int NUM_ROWS = 20;
-    private final Handler mHandler = new Handler();
-    private Timer mAutoScrollTimer;
-    private int mAutoScrollCount;
-
-    private ArrayObjectAdapter mRowsAdapter;
-    private DisplayMetrics mMetrics;
-    private BackgroundManager mBackgroundManager;
-
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-
-        buildRowAdapterItems(VideoProvider.buildMedia(NUM_ROWS));
-        prepareBackgroundManager();
-        setupUIElements();
-        setupEventListeners();
-        Intent intent = getActivity().getIntent();
-        if (intent.getExtras() != null) {
-            int initialDelay = intent.getExtras().getInt(IntentKeys.SCROLL_DELAY);
-            int scrollCount = intent.getExtras().getInt(IntentKeys.SCROLL_COUNT);
-            int scrollInterval = intent.getExtras().getInt(IntentKeys.SCROLL_INTERVAL);
-            if (scrollInterval != 0 && scrollCount != 0) {
-                startAutoScrollTimer(initialDelay, scrollInterval, scrollCount);
-            }
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        if (null != mAutoScrollTimer) {
-            mAutoScrollTimer.cancel();
-            mAutoScrollTimer = null;
-        }
-        super.onDestroy();
-    }
-
-    @Override
-    public void onStop() {
-        mBackgroundManager.release();
-        super.onStop();
-    }
-
-    private void prepareBackgroundManager() {
-        mBackgroundManager = BackgroundManager.getInstance(getActivity());
-        mBackgroundManager.attach(getActivity().getWindow());
-        mBackgroundManager.setDrawable(getActivity().getResources().getDrawable(
-                R.drawable.default_background, getContext().getTheme()));
-        mMetrics = new DisplayMetrics();
-        getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
-    }
-
-    private void setupUIElements() {
-        setBadgeDrawable(getActivity().getResources().getDrawable(
-                R.drawable.videos_by_google_banner, getContext().getTheme()));
-        setTitle(getString(R.string.browse_title));
-        setHeadersState(HEADERS_ENABLED);
-        setHeadersTransitionOnBackEnabled(true);
-
-        Theme theme = getContext().getTheme();
-        setBrandColor(getResources().getColor(R.color.fastlane_background, theme));
-
-        setSearchAffordanceColor(getResources().getColor(R.color.search_opaque, theme));
-
-        setHeaderPresenterSelector(new PresenterSelector() {
-            @Override
-            public Presenter getPresenter(Object o) {
-                return new IconHeaderItemPresenter();
-            }
-        });
-    }
-
-    private void setupEventListeners() {
-        // Add lister to show the search button.
-        setOnSearchClickedListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-            }
-        });
-    }
-
-    public void buildRowAdapterItems(HashMap<String, List<Movie>> data) {
-        mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
-        CardPresenter cardPresenter = new CardPresenter();
-
-        int i = 0;
-
-        for (Map.Entry<String, List<Movie>> entry : data.entrySet()) {
-            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
-            List<Movie> list = entry.getValue();
-
-            for (int j = 0; j < list.size(); j++) {
-                listRowAdapter.add(list.get(j));
-            }
-            HeaderItem header = new HeaderItem(i, entry.getKey());
-            i++;
-            mRowsAdapter.add(new ListRow(header, listRowAdapter));
-        }
-
-        HeaderItem gridHeader = new HeaderItem(i, getString(R.string.settings));
-
-        GridItemPresenter gridPresenter = new GridItemPresenter(this);
-        ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(gridPresenter);
-        for (int j = 0; j < 10; j++) {
-            gridRowAdapter.add(getString(R.string.grid_item_template, j));
-        }
-        mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));
-
-        setAdapter(mRowsAdapter);
-    }
-
-    private class UpdateAutoScrollTask extends TimerTask {
-        @Override
-        public void run() {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    if (mAutoScrollCount == 0) {
-                      mAutoScrollTimer.cancel();
-                      return;
-                    }
-                    if (mAutoScrollCount % 2 == 0) {
-                      setSelectedPosition(NUM_ROWS - 1);
-                    } else {
-                      setSelectedPosition(0);
-                    }
-                    mAutoScrollCount--;
-                }
-            });
-        }
-    }
-
-    private void startAutoScrollTimer(int initialDelay, int interval, int count) {
-        if (null != mAutoScrollTimer) {
-            mAutoScrollTimer.cancel();
-        }
-        mAutoScrollCount = count;
-        mAutoScrollTimer = new Timer();
-        mAutoScrollTimer.schedule(new UpdateAutoScrollTask(), initialDelay, interval);
-    }
-
-    public void selectRow(int row) {
-        setSelectedPosition(row);
-    }
-}
diff --git a/tests/leanbackjank/app/src/android/leanbackjank/app/IntentKeys.java b/tests/leanbackjank/app/src/android/leanbackjank/app/IntentKeys.java
new file mode 100644
index 0000000..b459aa9
--- /dev/null
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/IntentKeys.java
@@ -0,0 +1,10 @@
+package android.leanbackjank.app;
+
+/**
+ * Intent key strings of the leanback jank test helper app.
+ */
+public class IntentKeys {
+    public static final String SCROLL_COUNT = "SCROLL_COUNT";
+    public static final String SCROLL_DELAY = "SCROLL_DELAY";
+    public static final String SCROLL_INTERVAL = "SCROLL_INTERVAL";
+}
diff --git a/tests/leanbackjank/app/src/android/leanbackjank/app/Utils.java b/tests/leanbackjank/app/src/android/leanbackjank/app/Utils.java
new file mode 100644
index 0000000..b464abf
--- /dev/null
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/Utils.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 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.leanbackjank.app;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Point;
+import android.media.MediaMetadataRetriever;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.Toast;
+import android.widget.VideoView;
+
+import java.util.HashMap;
+
+/**
+ * A collection of utility methods, all static.
+ */
+public class Utils {
+
+    public interface MediaDimensions {
+        double MEDIA_HEIGHT = 0.95;
+        double MEDIA_WIDTH = 0.95;
+        double MEDIA_TOP_MARGIN = 0.025;
+        double MEDIA_RIGHT_MARGIN = 0.025;
+        double MEDIA_BOTTOM_MARGIN = 0.025;
+        double MEDIA_LEFT_MARGIN = 0.025;
+    }
+
+    /*
+     * Making sure public utility methods remain static
+     */
+    private Utils() {
+    }
+
+    /**
+     * Returns the screen/display size
+     */
+    public static Point getDisplaySize(Context context) {
+        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        Display display = wm.getDefaultDisplay();
+        Point size = new Point();
+        display.getSize(size);
+        return size;
+    }
+
+    /**
+     * Shows a (long) toast
+     */
+    public static void showToast(Context context, String msg) {
+        Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
+    }
+
+    /**
+     * Shows a (long) toast.
+     */
+    public static void showToast(Context context, int resourceId) {
+        Toast.makeText(context, context.getString(resourceId), Toast.LENGTH_LONG).show();
+    }
+
+    public static int convertDpToPixel(Context ctx, int dp) {
+        float density = ctx.getResources().getDisplayMetrics().density;
+        return Math.round((float) dp * density);
+    }
+
+
+    /**
+     * Example for handling resizing content for overscan.  Typically you won't need to resize
+     * when using the Leanback support library.
+     */
+    public void overScan(Activity activity, VideoView videoView) {
+        DisplayMetrics metrics = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int w = (int) (metrics.widthPixels * MediaDimensions.MEDIA_WIDTH);
+        int h = (int) (metrics.heightPixels * MediaDimensions.MEDIA_HEIGHT);
+        int marginLeft = (int) (metrics.widthPixels * MediaDimensions.MEDIA_LEFT_MARGIN);
+        int marginTop = (int) (metrics.heightPixels * MediaDimensions.MEDIA_TOP_MARGIN);
+        int marginRight = (int) (metrics.widthPixels * MediaDimensions.MEDIA_RIGHT_MARGIN);
+        int marginBottom = (int) (metrics.heightPixels * MediaDimensions.MEDIA_BOTTOM_MARGIN);
+        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(w, h);
+        lp.setMargins(marginLeft, marginTop, marginRight, marginBottom);
+        videoView.setLayoutParams(lp);
+    }
+
+
+    public static long getDuration(String videoUrl) {
+        MediaMetadataRetriever mmr = new MediaMetadataRetriever();
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            mmr.setDataSource(videoUrl, new HashMap<String, String>());
+        } else {
+            mmr.setDataSource(videoUrl);
+        }
+        return Long.parseLong(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
+    }
+}
diff --git a/tests/leanbackjank/app/src/android/leanbackjank/app/data/VideoProvider.java b/tests/leanbackjank/app/src/android/leanbackjank/app/data/VideoProvider.java
new file mode 100644
index 0000000..6ea19c1
--- /dev/null
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/data/VideoProvider.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 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.leanbackjank.app.data;
+
+import android.leanbackjank.app.model.Movie;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Provides synthesized movie data.
+ */
+public class VideoProvider {
+    private static HashMap<String, List<Movie>> sMovieList;
+    private static HashMap<String, Movie> sMovieListById;
+
+    public static Movie getMovieById(String mediaId) {
+        return sMovieListById.get(mediaId);
+    }
+
+    public static HashMap<String, List<Movie>> getMovieList() {
+        return sMovieList;
+    }
+
+    public static HashMap<String, List<Movie>> buildMedia(int nCategories) {
+        if (null != sMovieList) {
+            return sMovieList;
+        }
+        sMovieList = new HashMap<>();
+        sMovieListById = new HashMap<>();
+
+        String title = new String();
+        String studio = new String();
+        for (int i = 0; i < nCategories; i++) {
+            String category_name = String.format("Category %d",  i);
+            List<Movie> categoryList = new ArrayList<Movie>();
+            for (int j = 0; j < 20; j++) {
+                String description = "This is description of a movie.";
+                title = String.format("Video %d-%d", i, j);
+                studio = String.format("Studio %d", (i + j) % 7);
+                Movie movie = buildMovieInfo(category_name, title, description, studio);
+                sMovieListById.put(movie.getId(), movie);
+                categoryList.add(movie);
+            }
+            sMovieList.put(category_name, categoryList);
+        }
+        return sMovieList;
+    }
+
+    private static Movie buildMovieInfo(String category,
+                                        String title,
+                                        String description,
+                                        String studio) {
+        Movie movie = new Movie();
+        movie.setId(Movie.getCount());
+        Movie.incrementCount();
+        movie.setTitle(title);
+        movie.setDescription(description);
+        movie.setStudio(studio);
+        movie.setCategory(category);
+
+        return movie;
+    }
+}
diff --git a/tests/leanbackjank/app/src/android/leanbackjank/app/model/Movie.java b/tests/leanbackjank/app/src/android/leanbackjank/app/model/Movie.java
new file mode 100644
index 0000000..1b68aee
--- /dev/null
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/model/Movie.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 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.leanbackjank.app.model;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Movie class represents video entity with title, description, image thumbs and video url.
+ */
+public class Movie implements Parcelable {
+    static final long serialVersionUID = 727566175075960653L;
+    private static int sCount = 0;
+    private String mId;
+    private String mTitle;
+    private String mDescription;
+    private String mStudio;
+    private String mCategory;
+
+    public Movie() {
+    }
+
+    public Movie(Parcel in){
+        String[] data = new String[5];
+
+        in.readStringArray(data);
+        mId = data[0];
+        mTitle = data[1];
+        mDescription = data[2];
+        mStudio = data[3];
+        mCategory = data[4];
+    }
+
+    public static String getCount() {
+        return Integer.toString(sCount);
+    }
+
+    public static void incrementCount() {
+        sCount++;
+    }
+
+    public String getId() {
+        return mId;
+    }
+
+    public void setId(String id) {
+        mId = id;
+    }
+
+    public String getTitle() {
+        return mTitle;
+    }
+
+    public void setTitle(String title) {
+        mTitle = title;
+    }
+
+    public String getDescription() {
+        return mDescription;
+    }
+
+    public void setDescription(String description) {
+        mDescription = description;
+    }
+
+    public String getStudio() {
+        return mStudio;
+    }
+
+    public void setStudio(String studio) {
+        mStudio = studio;
+    }
+
+    public String getCategory() {
+        return mCategory;
+    }
+
+    public void setCategory(String category) {
+        mCategory = category;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStringArray(new String[] {mId,
+                mTitle,
+                mDescription,
+                mStudio,
+                mCategory});
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(200);
+        sb.append("Movie{");
+        sb.append("mId=" + mId);
+        sb.append(", mTitle='" + mTitle + '\'');
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+        public Movie createFromParcel(Parcel in) {
+            return new Movie(in);
+        }
+
+        public Movie[] newArray(int size) {
+            return new Movie[size];
+        }
+    };
+}
diff --git a/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/CardPresenter.java b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/CardPresenter.java
new file mode 100644
index 0000000..f237438
--- /dev/null
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/CardPresenter.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 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.leanbackjank.app.presenter;
+
+import android.graphics.drawable.Drawable;
+import android.support.v17.leanback.widget.ImageCardView;
+import android.support.v17.leanback.widget.Presenter;
+import android.view.ViewGroup;
+
+import com.bumptech.glide.Glide;
+import android.leanbackjank.app.R;
+import android.leanbackjank.app.model.Movie;
+
+/**
+ * A CardPresenter is used to generate Views and bind Objects to them on demand.
+ * It contains an Image CardView
+ */
+public class CardPresenter extends Presenter {
+    private static int CARD_WIDTH = 313;
+    private static int CARD_HEIGHT = 176;
+    private static int sSelectedBackgroundColor;
+    private static int sDefaultBackgroundColor;
+    private Drawable mDefaultCardImage;
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup parent) {
+        sDefaultBackgroundColor = parent.getResources().getColor(R.color.default_background, null);
+        sSelectedBackgroundColor =
+                parent.getResources().getColor(R.color.selected_background, null);
+        mDefaultCardImage = parent.getResources().getDrawable(R.drawable.movie, null);
+
+        ImageCardView cardView = new ImageCardView(parent.getContext()) {
+            @Override
+            public void setSelected(boolean selected) {
+                updateCardBackgroundColor(this, selected);
+                super.setSelected(selected);
+            }
+        };
+
+        cardView.setFocusable(true);
+        cardView.setFocusableInTouchMode(true);
+        updateCardBackgroundColor(cardView, false);
+        return new ViewHolder(cardView);
+    }
+
+    private static void updateCardBackgroundColor(ImageCardView view, boolean selected) {
+        int color = selected ? sSelectedBackgroundColor : sDefaultBackgroundColor;
+        // Both background colors should be set because the view's background is temporarily visible
+        // during animations.
+        view.setBackgroundColor(color);
+        view.findViewById(R.id.info_field).setBackgroundColor(color);
+    }
+
+    @Override
+    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
+        Movie movie = (Movie) item;
+        ImageCardView cardView = (ImageCardView) viewHolder.view;
+
+        cardView.setTitleText(movie.getTitle());
+        cardView.setContentText(movie.getStudio());
+        cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT);
+        Glide.with(viewHolder.view.getContext())
+                .load(R.drawable.gradation)
+                .centerCrop()
+                .error(mDefaultCardImage)
+                .into(cardView.getMainImageView());
+    }
+
+    @Override
+    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
+        ImageCardView cardView = (ImageCardView) viewHolder.view;
+        // Remove references to images so that the garbage collector can free up memory
+        cardView.setBadgeImage(null);
+        cardView.setMainImage(null);
+    }
+}
diff --git a/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/GridItemPresenter.java b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/GridItemPresenter.java
new file mode 100644
index 0000000..1ab7e8d
--- /dev/null
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/GridItemPresenter.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 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.leanbackjank.app.presenter;
+
+import android.graphics.Color;
+import android.support.v17.leanback.widget.Presenter;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import android.leanbackjank.app.R;
+import android.leanbackjank.app.ui.MainFragment;
+
+public class GridItemPresenter extends Presenter {
+    private static int GRID_ITEM_WIDTH = 200;
+    private static int GRID_ITEM_HEIGHT = 200;
+
+    private MainFragment mainFragment;
+
+    public GridItemPresenter(MainFragment mainFragment) {
+        this.mainFragment = mainFragment;
+    }
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup parent) {
+        TextView view = new TextView(parent.getContext());
+        view.setLayoutParams(new ViewGroup.LayoutParams(GRID_ITEM_WIDTH, GRID_ITEM_HEIGHT));
+        view.setFocusable(true);
+        view.setFocusableInTouchMode(true);
+        view.setBackgroundColor(
+            mainFragment.getResources().getColor(R.color.default_background, null));
+        view.setTextColor(Color.WHITE);
+        view.setGravity(Gravity.CENTER);
+        return new ViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder viewHolder, Object item) {
+        ((TextView) viewHolder.view).setText((String) item);
+    }
+
+    @Override
+    public void onUnbindViewHolder(ViewHolder viewHolder) {
+    }
+}
diff --git a/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/IconHeaderItemPresenter.java b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/IconHeaderItemPresenter.java
new file mode 100644
index 0000000..32dae35
--- /dev/null
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/IconHeaderItemPresenter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 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.leanbackjank.app.presenter;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.RowHeaderPresenter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import android.leanbackjank.app.R;
+
+public class IconHeaderItemPresenter extends RowHeaderPresenter {
+    private float mUnselectedAlpha;
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup viewGroup) {
+        mUnselectedAlpha = viewGroup.getResources()
+                .getFraction(R.fraction.lb_browse_header_unselect_alpha, 1, 1);
+        LayoutInflater inflater = (LayoutInflater) viewGroup.getContext()
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        View view = inflater.inflate(R.layout.icon_header_item, null);
+
+        return new ViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object o) {
+        HeaderItem headerItem = ((ListRow) o).getHeaderItem();
+        View rootView = viewHolder.view;
+
+        ImageView iconView = (ImageView) rootView.findViewById(R.id.header_icon);
+        Drawable icon = rootView.getResources().getDrawable(R.drawable.android_header, null);
+        iconView.setImageDrawable(icon);
+
+        TextView label = (TextView) rootView.findViewById(R.id.header_label);
+        label.setText(headerItem.getName());
+    }
+
+    @Override
+    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
+    }
+
+    // TODO: TEMP - remove me when leanback onCreateViewHolder no longer sets the mUnselectAlpha,AND
+    // also assumes the xml inflation will return a RowHeaderView
+    @Override
+    protected void onSelectLevelChanged(RowHeaderPresenter.ViewHolder holder) {
+        // this is a temporary fix
+        holder.view.setAlpha(mUnselectedAlpha + holder.getSelectLevel() *
+                (1.0f - mUnselectedAlpha));
+    }
+}
diff --git a/tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainActivity.java b/tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainActivity.java
new file mode 100644
index 0000000..356c2ac
--- /dev/null
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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.leanbackjank.app.ui;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.leanbackjank.app.R;
+
+/**
+ * MainActivity class that loads MainFragment
+ */
+public class MainActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+    }
+
+    @Override
+    public boolean onSearchRequested() {
+        return false;
+    }
+}
diff --git a/tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainFragment.java b/tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainFragment.java
new file mode 100644
index 0000000..2119b2f
--- /dev/null
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainFragment.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2015 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.leanbackjank.app.ui;
+
+import android.content.Intent;
+import android.content.res.Resources.Theme;
+import android.leanbackjank.app.IntentKeys;
+import android.leanbackjank.app.R;
+import android.leanbackjank.app.data.VideoProvider;
+import android.leanbackjank.app.model.Movie;
+import android.leanbackjank.app.presenter.CardPresenter;
+import android.leanbackjank.app.presenter.GridItemPresenter;
+import android.leanbackjank.app.presenter.IconHeaderItemPresenter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v17.leanback.app.BackgroundManager;
+import android.support.v17.leanback.app.BrowseFragment;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.util.DisplayMetrics;
+import android.view.View;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Main class to show BrowseFragment with header and rows of videos
+ */
+public class MainFragment extends BrowseFragment {
+    private static final int NUM_ROWS = 20;
+    private final Handler mHandler = new Handler();
+    private Timer mAutoScrollTimer;
+    private int mAutoScrollCount;
+
+    private ArrayObjectAdapter mRowsAdapter;
+    private DisplayMetrics mMetrics;
+    private BackgroundManager mBackgroundManager;
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        buildRowAdapterItems(VideoProvider.buildMedia(NUM_ROWS));
+        prepareBackgroundManager();
+        setupUIElements();
+        setupEventListeners();
+        Intent intent = getActivity().getIntent();
+        if (intent.getExtras() != null) {
+            int initialDelay = intent.getExtras().getInt(IntentKeys.SCROLL_DELAY);
+            int scrollCount = intent.getExtras().getInt(IntentKeys.SCROLL_COUNT);
+            int scrollInterval = intent.getExtras().getInt(IntentKeys.SCROLL_INTERVAL);
+            if (scrollInterval != 0 && scrollCount != 0) {
+                startAutoScrollTimer(initialDelay, scrollInterval, scrollCount);
+            }
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        if (null != mAutoScrollTimer) {
+            mAutoScrollTimer.cancel();
+            mAutoScrollTimer = null;
+        }
+        super.onDestroy();
+    }
+
+    @Override
+    public void onStop() {
+        mBackgroundManager.release();
+        super.onStop();
+    }
+
+    private void prepareBackgroundManager() {
+        mBackgroundManager = BackgroundManager.getInstance(getActivity());
+        mBackgroundManager.attach(getActivity().getWindow());
+        mBackgroundManager.setDrawable(getActivity().getResources().getDrawable(
+                R.drawable.default_background, getContext().getTheme()));
+        mMetrics = new DisplayMetrics();
+        getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
+    }
+
+    private void setupUIElements() {
+        setBadgeDrawable(getActivity().getResources().getDrawable(
+                R.drawable.videos_by_google_banner, getContext().getTheme()));
+        setTitle(getString(R.string.browse_title));
+        setHeadersState(HEADERS_ENABLED);
+        setHeadersTransitionOnBackEnabled(true);
+
+        Theme theme = getContext().getTheme();
+        setBrandColor(getResources().getColor(R.color.fastlane_background, theme));
+
+        setSearchAffordanceColor(getResources().getColor(R.color.search_opaque, theme));
+
+        setHeaderPresenterSelector(new PresenterSelector() {
+            @Override
+            public Presenter getPresenter(Object o) {
+                return new IconHeaderItemPresenter();
+            }
+        });
+    }
+
+    private void setupEventListeners() {
+        // Add lister to show the search button.
+        setOnSearchClickedListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+            }
+        });
+    }
+
+    public void buildRowAdapterItems(HashMap<String, List<Movie>> data) {
+        mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
+        CardPresenter cardPresenter = new CardPresenter();
+
+        int i = 0;
+
+        for (Map.Entry<String, List<Movie>> entry : data.entrySet()) {
+            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
+            List<Movie> list = entry.getValue();
+
+            for (int j = 0; j < list.size(); j++) {
+                listRowAdapter.add(list.get(j));
+            }
+            HeaderItem header = new HeaderItem(i, entry.getKey());
+            i++;
+            mRowsAdapter.add(new ListRow(header, listRowAdapter));
+        }
+
+        HeaderItem gridHeader = new HeaderItem(i, getString(R.string.settings));
+
+        GridItemPresenter gridPresenter = new GridItemPresenter(this);
+        ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(gridPresenter);
+        for (int j = 0; j < 10; j++) {
+            gridRowAdapter.add(getString(R.string.grid_item_template, j));
+        }
+        mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));
+
+        setAdapter(mRowsAdapter);
+    }
+
+    private class UpdateAutoScrollTask extends TimerTask {
+        @Override
+        public void run() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    if (mAutoScrollCount == 0) {
+                      mAutoScrollTimer.cancel();
+                      return;
+                    }
+                    if (mAutoScrollCount % 2 == 0) {
+                      setSelectedPosition(NUM_ROWS - 1);
+                    } else {
+                      setSelectedPosition(0);
+                    }
+                    mAutoScrollCount--;
+                }
+            });
+        }
+    }
+
+    private void startAutoScrollTimer(int initialDelay, int interval, int count) {
+        if (null != mAutoScrollTimer) {
+            mAutoScrollTimer.cancel();
+        }
+        mAutoScrollCount = count;
+        mAutoScrollTimer = new Timer();
+        mAutoScrollTimer.schedule(new UpdateAutoScrollTask(), initialDelay, interval);
+    }
+
+    public void selectRow(int row) {
+        setSelectedPosition(row);
+    }
+}
diff --git a/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java b/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
deleted file mode 100644
index 241535e..0000000
--- a/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.leanbackjank;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.cts.jank.leanback.IntentKeys;
-import android.os.SystemClock;
-import android.support.test.jank.GfxMonitor;
-import android.support.test.jank.JankTest;
-import android.support.test.jank.WindowContentFrameStatsMonitor;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.Until;
-import android.util.Log;
-
-public class CtsDeviceLeanback extends CtsJankTestBase {
-    private static final String TAG = "CtsDeviceLeanback";
-    private static final int MILLIS_PER_SECOND = 1000;
-    private static final long WAIT_TIMEOUT = 5 * MILLIS_PER_SECOND;
-    private static final int SCROLL_COUNT = 100;
-    private static final int SCROLL_INTERVAL_MILLIS = 200;
-    private static final int PRE_SCROLL_DELAY_MILLIS = 0;
-    private static final int PRE_SCROLL_IDLE_TIME = 2 * MILLIS_PER_SECOND;
-    private static final int SAMPLING_DURATION_SECONDS = 3;
-    private static final int SAMPLING_DURATION_MILLIS =
-            SAMPLING_DURATION_SECONDS * MILLIS_PER_SECOND;
-    private final static String APP_PACKAGE = "android.cts.jank.leanback";
-    private final static String JAVA_PACKAGE = "android.cts.jank.leanback.ui";
-    private final static String CLASS = JAVA_PACKAGE + ".MainActivity";
-
-    private boolean shouldSkip() {
-	PackageManager packageManager =
-                getInstrumentation().getTargetContext().getPackageManager();
-        if (!packageManager.hasSystemFeature(
-                PackageManager.FEATURE_LEANBACK)) {
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    protected void runTest() throws Throwable {
-        if (shouldSkip()) {
-            return;
-        }
-        super.runTest();
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        if (shouldSkip()) {
-            return;
-        }
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setComponent(new ComponentName(APP_PACKAGE, CLASS));
-
-        // Trigger automated scroll of the helper app.
-        intent.putExtra(IntentKeys.SCROLL_DELAY, PRE_SCROLL_DELAY_MILLIS);
-        intent.putExtra(IntentKeys.SCROLL_COUNT, SCROLL_COUNT);
-        intent.putExtra(IntentKeys.SCROLL_INTERVAL, SCROLL_INTERVAL_MILLIS);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        getInstrumentation().getTargetContext().startActivity(intent);
-        if (!getUiDevice().wait(Until.hasObject(By.pkg(APP_PACKAGE)), WAIT_TIMEOUT)) {
-            fail("Test helper app package not found on device");
-        }
-
-        // Wait until scroll animation starts.
-        SystemClock.sleep(PRE_SCROLL_IDLE_TIME);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        getUiDevice().pressHome();
-        super.tearDown();
-    }
-
-    // Requires at least 30 fps on average to pass the test.
-    @JankTest(expectedFrames = 30 * SAMPLING_DURATION_SECONDS, defaultIterationCount = 2)
-    @GfxMonitor(processName = APP_PACKAGE)
-    @WindowContentFrameStatsMonitor
-    public void testScrollingByTimer() {
-        SystemClock.sleep(SAMPLING_DURATION_MILLIS);
-    }
-}
diff --git a/tests/leanbackjank/src/android/cts/leanbackjank/CtsJankTestBase.java b/tests/leanbackjank/src/android/cts/leanbackjank/CtsJankTestBase.java
deleted file mode 100644
index 4de0702..0000000
--- a/tests/leanbackjank/src/android/cts/leanbackjank/CtsJankTestBase.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2015 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.cts.leanbackjank;
-
-import android.cts.util.DeviceReportLog;
-import android.os.Bundle;
-import android.support.test.jank.GfxMonitor;
-import android.support.test.jank.JankTestBase;
-import android.support.test.jank.WindowContentFrameStatsMonitor;
-import android.support.test.uiautomator.UiDevice;
-
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-
-public abstract class CtsJankTestBase extends JankTestBase {
-
-    private UiDevice mDevice;
-    private DeviceReportLog mLog;
-
-    private void printIntValueWithKey(String source, Bundle metrics, String key,
-            ResultType resultType, ResultUnit resultUnit) {
-        if (!metrics.containsKey(key)) {
-            return;
-        }
-        mLog.printValue(source, key, metrics.getInt(key), resultType, resultUnit);
-    }
-
-    private void printDoubleValueWithKey(String source, Bundle metrics, String key,
-            ResultType resultType, ResultUnit resultUnit) {
-        if (!metrics.containsKey(key)) {
-            return;
-        }
-        mLog.printValue(source, key, metrics.getDouble(key), resultType, resultUnit);
-    }
-
-    @Override
-    public void afterTest(Bundle metrics) {
-        String source = String.format("%s#%s", getClass().getCanonicalName(), getName());
-        printDoubleValueWithKey(source, metrics, WindowContentFrameStatsMonitor.KEY_AVG_FPS,
-                ResultType.HIGHER_BETTER, ResultUnit.FPS);
-        printDoubleValueWithKey(source, metrics,
-                WindowContentFrameStatsMonitor.KEY_AVG_LONGEST_FRAME,
-                ResultType.LOWER_BETTER, ResultUnit.MS);
-        printIntValueWithKey(source, metrics, WindowContentFrameStatsMonitor.KEY_MAX_NUM_JANKY,
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-        mLog.printSummary(WindowContentFrameStatsMonitor.KEY_AVG_NUM_JANKY,
-                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_NUM_JANKY),
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-
-        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_NUM_JANKY,
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_FRAME_TIME_90TH_PERCENTILE,
-                ResultType.LOWER_BETTER, ResultUnit.MS);
-        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_FRAME_TIME_95TH_PERCENTILE,
-                ResultType.LOWER_BETTER, ResultUnit.MS);
-        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_FRAME_TIME_99TH_PERCENTILE,
-                ResultType.LOWER_BETTER, ResultUnit.MS);
-        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_MISSED_VSYNC,
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_SLOW_UI_THREAD,
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_SLOW_BITMAP_UPLOADS,
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_SLOW_DRAW,
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_HIGH_INPUT_LATENCY,
-                ResultType.LOWER_BETTER, ResultUnit.COUNT);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mLog = new DeviceReportLog();
-        // fix device orientation
-        mDevice = UiDevice.getInstance(getInstrumentation());
-        mDevice.setOrientationNatural();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mLog.deliverReportToHost(getInstrumentation());
-        // restore device orientation
-        mDevice.unfreezeRotation();
-        super.tearDown();
-    }
-
-    protected UiDevice getUiDevice() {
-        return mDevice;
-    }
-}
diff --git a/tests/leanbackjank/src/android/leanbackjank/cts/CtsDeviceLeanback.java b/tests/leanbackjank/src/android/leanbackjank/cts/CtsDeviceLeanback.java
new file mode 100644
index 0000000..c52fe09
--- /dev/null
+++ b/tests/leanbackjank/src/android/leanbackjank/cts/CtsDeviceLeanback.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 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.leanbackjank.cts;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.leanbackjank.app.IntentKeys;
+import android.os.SystemClock;
+import android.support.test.jank.GfxMonitor;
+import android.support.test.jank.JankTest;
+import android.support.test.jank.WindowContentFrameStatsMonitor;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.Until;
+import android.util.Log;
+
+public class CtsDeviceLeanback extends CtsJankTestBase {
+    private static final String TAG = "CtsDeviceLeanback";
+    private static final int MILLIS_PER_SECOND = 1000;
+    private static final long WAIT_TIMEOUT = 5 * MILLIS_PER_SECOND;
+    private static final int SCROLL_COUNT = 100;
+    private static final int SCROLL_INTERVAL_MILLIS = 200;
+    private static final int PRE_SCROLL_DELAY_MILLIS = 0;
+    private static final int PRE_SCROLL_IDLE_TIME = 2 * MILLIS_PER_SECOND;
+    private static final int SAMPLING_DURATION_SECONDS = 3;
+    private static final int SAMPLING_DURATION_MILLIS =
+            SAMPLING_DURATION_SECONDS * MILLIS_PER_SECOND;
+    private final static String APP_PACKAGE = "android.leanbackjank.app";
+    private final static String JAVA_PACKAGE = "android.leanbackjank.app.ui";
+    private final static String CLASS = JAVA_PACKAGE + ".MainActivity";
+
+    private boolean shouldSkip() {
+	PackageManager packageManager =
+                getInstrumentation().getTargetContext().getPackageManager();
+        if (!packageManager.hasSystemFeature(
+                PackageManager.FEATURE_LEANBACK)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    protected void runTest() throws Throwable {
+        if (shouldSkip()) {
+            return;
+        }
+        super.runTest();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        if (shouldSkip()) {
+            return;
+        }
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setComponent(new ComponentName(APP_PACKAGE, CLASS));
+
+        // Trigger automated scroll of the helper app.
+        intent.putExtra(IntentKeys.SCROLL_DELAY, PRE_SCROLL_DELAY_MILLIS);
+        intent.putExtra(IntentKeys.SCROLL_COUNT, SCROLL_COUNT);
+        intent.putExtra(IntentKeys.SCROLL_INTERVAL, SCROLL_INTERVAL_MILLIS);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        getInstrumentation().getTargetContext().startActivity(intent);
+        if (!getUiDevice().wait(Until.hasObject(By.pkg(APP_PACKAGE)), WAIT_TIMEOUT)) {
+            fail("Test helper app package not found on device");
+        }
+
+        // Wait until scroll animation starts.
+        SystemClock.sleep(PRE_SCROLL_IDLE_TIME);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        getUiDevice().pressHome();
+        super.tearDown();
+    }
+
+    // Requires at least 30 fps on average to pass the test.
+    @JankTest(expectedFrames = 30 * SAMPLING_DURATION_SECONDS, defaultIterationCount = 2)
+    @GfxMonitor(processName = APP_PACKAGE)
+    @WindowContentFrameStatsMonitor
+    public void testScrollingByTimer() {
+        SystemClock.sleep(SAMPLING_DURATION_MILLIS);
+    }
+}
diff --git a/tests/leanbackjank/src/android/leanbackjank/cts/CtsJankTestBase.java b/tests/leanbackjank/src/android/leanbackjank/cts/CtsJankTestBase.java
new file mode 100644
index 0000000..77a1d1c
--- /dev/null
+++ b/tests/leanbackjank/src/android/leanbackjank/cts/CtsJankTestBase.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 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.leanbackjank.cts;
+
+import android.cts.util.DeviceReportLog;
+import android.os.Bundle;
+import android.support.test.jank.GfxMonitor;
+import android.support.test.jank.JankTestBase;
+import android.support.test.jank.WindowContentFrameStatsMonitor;
+import android.support.test.uiautomator.UiDevice;
+
+import com.android.cts.util.ResultType;
+import com.android.cts.util.ResultUnit;
+
+public abstract class CtsJankTestBase extends JankTestBase {
+
+    private UiDevice mDevice;
+    private DeviceReportLog mLog;
+
+    private void printIntValueWithKey(String source, Bundle metrics, String key,
+            ResultType resultType, ResultUnit resultUnit) {
+        if (!metrics.containsKey(key)) {
+            return;
+        }
+        mLog.printValue(source, key, metrics.getInt(key), resultType, resultUnit);
+    }
+
+    private void printDoubleValueWithKey(String source, Bundle metrics, String key,
+            ResultType resultType, ResultUnit resultUnit) {
+        if (!metrics.containsKey(key)) {
+            return;
+        }
+        mLog.printValue(source, key, metrics.getDouble(key), resultType, resultUnit);
+    }
+
+    @Override
+    public void afterTest(Bundle metrics) {
+        String source = String.format("%s#%s", getClass().getCanonicalName(), getName());
+        printDoubleValueWithKey(source, metrics, WindowContentFrameStatsMonitor.KEY_AVG_FPS,
+                ResultType.HIGHER_BETTER, ResultUnit.FPS);
+        printDoubleValueWithKey(source, metrics,
+                WindowContentFrameStatsMonitor.KEY_AVG_LONGEST_FRAME,
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        printIntValueWithKey(source, metrics, WindowContentFrameStatsMonitor.KEY_MAX_NUM_JANKY,
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        mLog.printSummary(WindowContentFrameStatsMonitor.KEY_AVG_NUM_JANKY,
+                metrics.getDouble(WindowContentFrameStatsMonitor.KEY_AVG_NUM_JANKY),
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+
+        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_NUM_JANKY,
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_FRAME_TIME_90TH_PERCENTILE,
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_FRAME_TIME_95TH_PERCENTILE,
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_FRAME_TIME_99TH_PERCENTILE,
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_MISSED_VSYNC,
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_SLOW_UI_THREAD,
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_SLOW_BITMAP_UPLOADS,
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_SLOW_DRAW,
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        printDoubleValueWithKey(source, metrics, GfxMonitor.KEY_AVG_HIGH_INPUT_LATENCY,
+                ResultType.LOWER_BETTER, ResultUnit.COUNT);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mLog = new DeviceReportLog();
+        // fix device orientation
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        mDevice.setOrientationNatural();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mLog.deliverReportToHost(getInstrumentation());
+        // restore device orientation
+        mDevice.unfreezeRotation();
+        super.tearDown();
+    }
+
+    protected UiDevice getUiDevice() {
+        return mDevice;
+    }
+}
diff --git a/tests/libcore/Android.mk b/tests/libcore/Android.mk
new file mode 100644
index 0000000..cd1905d
--- /dev/null
+++ b/tests/libcore/Android.mk
@@ -0,0 +1,54 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsLibcoreTestCases
+
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests mockito-target
+
+LOCAL_JAVA_LIBRARIES := android-support-test android.test.runner bouncycastle conscrypt
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_JNI_SHARED_LIBRARIES := libjavacoretests
+
+# Include both the 32 and 64 bit versions of libjavacoretests,
+# where applicable.
+LOCAL_MULTILIB := both
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+# Copy the expectation files to CTS
+LOCAL_COMPATIBILITY_SUPPORT_FILES += \
+    ../../../art/tools/libcore_failures.txt:$(LOCAL_PACKAGE_NAME).failures.expectations \
+    ../../../libcore/expectations/brokentests.txt:$(LOCAL_PACKAGE_NAME).brokentests.expectations \
+    ../../../libcore/expectations/icebox.txt:$(LOCAL_PACKAGE_NAME).icebox.expectations \
+    ../../../libcore/expectations/knownfailures.txt:$(LOCAL_PACKAGE_NAME).knownfailures.expectations \
+    ../../../libcore/expectations/taggedtests.txt:$(LOCAL_PACKAGE_NAME).taggedtests.expectations
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/libcore/AndroidManifest.xml b/tests/libcore/AndroidManifest.xml
new file mode 100644
index 0000000..0389be6
--- /dev/null
+++ b/tests/libcore/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.libcore.cts">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.libcore.cts"
+                     android:label="CTS Libcore test cases" />
+
+</manifest>
diff --git a/tests/libcore/AndroidTest.xml b/tests/libcore/AndroidTest.xml
new file mode 100644
index 0000000..e71669a
--- /dev/null
+++ b/tests/libcore/AndroidTest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Libcore test cases">
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/ctslibcore/java.io.tmpdir" />
+        <option name="run-command" value="mkdir -p /data/local/tmp/ctslibcore/user.home" />
+        <option name="teardown-command" value="rm -rf /data/local/tmp/ctslibcore" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="cts-dalvik-device-test-runner.jar->/data/local/tmp/ctslibcore/cts-dalvik-device-test-runner.jar" />
+        <option name="push" value="CtsLibcoreTestCases.apk->/data/local/tmp/ctslibcore/CtsLibcoreTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.compatibility.testtype.DalvikTest" >
+        <option name="run-name" value="CtsLibcoreTestCases" />
+        <option name="classpath" value="/data/local/tmp/ctslibcore/cts-dalvik-device-test-runner.jar" />
+        <option name="expectations" value="CtsLibcoreTestCases.brokentests.expectations" />
+        <option name="expectations" value="CtsLibcoreTestCases.icebox.expectations" />
+        <option name="expectations" value="CtsLibcoreTestCases.knownfailures.expectations" />
+        <option name="expectations" value="CtsLibcoreTestCases.taggedtests.expectations" />
+        <option name="expectations" value="CtsLibcoreTestCases.failures.expectations" />
+        <option name="dalvik-arg" value="-Djava.io.tmpdir=/data/local/tmp/ctslibcore/java.io.tmpdir" />
+        <option name="dalvik-arg" value="-Duser.home=/data/local/tmp/ctslibcore/user.home" />
+        <option name="dalvik-arg" value="-Duser.name=shell" />
+        <option name="dalvik-arg" value="-Duser.language=en" />
+        <option name="dalvik-arg" value="-Duser.region=US" />
+        <option name="dalvik-arg" value="-Xcheck:jni" />
+        <option name="dalvik-arg" value="-Xjnigreflimit:2000" />
+        <option name="runner-arg" value="--apk=/data/local/tmp/ctslibcore/CtsLibcoreTestCases.apk" />
+    </test>
+</configuration>
diff --git a/tests/libcore/runner/Android.mk b/tests/libcore/runner/Android.mk
new file mode 100644
index 0000000..6b441a5
--- /dev/null
+++ b/tests/libcore/runner/Android.mk
@@ -0,0 +1,15 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+include $(call all-subdir-makefiles)
\ No newline at end of file
diff --git a/tests/libcore/runner/device-side/Android.mk b/tests/libcore/runner/device-side/Android.mk
new file mode 100644
index 0000000..ac5b0ca
--- /dev/null
+++ b/tests/libcore/runner/device-side/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := cts-dalvik-device-test-runner
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util
+
+# don't include these packages in any target
+LOCAL_MODULE_TAGS := optional
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+include $(BUILD_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/tests/libcore/runner/device-side/src/com/android/compatibility/dalvik/DalvikTestRunner.java b/tests/libcore/runner/device-side/src/com/android/compatibility/dalvik/DalvikTestRunner.java
new file mode 100644
index 0000000..56f48af
--- /dev/null
+++ b/tests/libcore/runner/device-side/src/com/android/compatibility/dalvik/DalvikTestRunner.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.dalvik;
+
+import com.android.compatibility.common.util.TestSuiteFilter;
+
+import dalvik.system.DexFile;
+import dalvik.system.PathClassLoader;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Scanner;
+import java.util.Set;
+
+/**
+ * Runs tests against the Dalvik VM.
+ */
+public class DalvikTestRunner {
+
+    private static final String ABI = "--abi=";
+    private static final String APK = "--apk=";
+    private static final String INCLUDE = "--include-filter=";
+    private static final String EXCLUDE = "--exclude-filter=";
+    private static final String INCLUDE_FILE = "--include-filter-file=";
+    private static final String EXCLUDE_FILE = "--exclude-filter-file=";
+    private static final String JUNIT_IGNORE = "org.junit.Ignore";
+
+    public static void main(String[] args) {
+        String abiName = null;
+        Set<String> apks = new HashSet<>();
+        Set<String> includes = new HashSet<>();
+        Set<String> excludes = new HashSet<>();
+        for (String arg : args) {
+            if (arg.startsWith(ABI)) {
+                abiName = arg.substring(ABI.length());
+            } else if (arg.startsWith(APK)) {
+                apks.add(arg.substring(APK.length()));
+            } else if (arg.startsWith(INCLUDE)) {
+                for (String include : arg.substring(INCLUDE.length()).split(",")) {
+                    includes.add(include);
+                }
+            } else if (arg.startsWith(EXCLUDE)) {
+                for (String exclude : arg.substring(EXCLUDE.length()).split(",")) {
+                    excludes.add(exclude);
+                }
+            } else if (arg.startsWith(INCLUDE_FILE)) {
+                loadFilters(arg.substring(INCLUDE_FILE.length()), includes);
+            } else if (arg.startsWith(EXCLUDE_FILE)) {
+                loadFilters(arg.substring(EXCLUDE_FILE.length()), excludes);
+            }
+        }
+        TestListener listener = new DalvikTestListener();
+        List<Class<?>> classes = getClasses(apks, abiName);
+        TestSuite suite = TestSuiteFilter.createSuite(classes, includes, excludes);
+        int count = suite.countTestCases();
+        System.out.println(String.format("start-run:%d", count));
+        long start = System.currentTimeMillis();
+        TestResult result = new TestResult();
+        result.addListener(listener);
+        suite.run(result);
+        long end = System.currentTimeMillis();
+        System.out.println(String.format("end-run:%d", end - start));
+    }
+
+    private static void loadFilters(String filename, Set<String> filters) {
+        try {
+            Scanner in = new Scanner(new File(filename));
+            while (in.hasNextLine()) {
+                filters.add(in.nextLine());
+            }
+            in.close();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static List<Class<?>> getClasses(Set<String> apks, String abiName) {
+        List<Class<?>> classes = new ArrayList<>();
+        for (String apk : apks) {
+            try {
+                ClassLoader loader = createClassLoader(apk, abiName);
+                DexFile file = new DexFile(apk);
+                Enumeration<String> entries = file.entries();
+                while (entries.hasMoreElements()) {
+                    String e = entries.nextElement();
+                    Class<?> cls = loader.loadClass(e);
+                    if (isTestClass(cls)) {
+                        classes.add(cls);
+                    }
+                }
+            } catch (IllegalAccessError | IOException | ClassNotFoundException e) {
+                e.printStackTrace();
+            }
+        }
+        return classes;
+    }
+
+    private static ClassLoader createClassLoader(String apk, String abiName) {
+        StringBuilder libPath = new StringBuilder();
+        libPath.append(apk).append("!/lib/").append(abiName);
+        return new PathClassLoader(apk, libPath.toString(), DalvikTestRunner.class.getClassLoader());
+    }
+
+    private static boolean isTestClass(Class<?> cls) {
+        // FIXME(b/25154702): have to have a null check here because some
+        // classes such as
+        // SQLite.JDBC2z.JDBCPreparedStatement can be found in the classes.dex
+        // by DexFile.entries
+        // but trying to load them with DexFile.loadClass returns null.
+        if (cls == null) {
+            return false;
+        }
+        for (Annotation a : cls.getAnnotations()) {
+            if (a.annotationType().getName().equals(JUNIT_IGNORE)) {
+                return false;
+            }
+        }
+        // TODO: Add junit4 support here
+        int modifiers = cls.getModifiers();
+        return (Test.class.isAssignableFrom(cls)
+                && Modifier.isPublic(modifiers)
+                && !Modifier.isStatic(modifiers)
+                && !Modifier.isInterface(modifiers)
+                && !Modifier.isAbstract(modifiers));
+    }
+
+    // TODO: expand this to setup and teardown things needed by Dalvik tests.
+    private static class DalvikTestListener implements TestListener {
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void startTest(Test test) {
+            System.out.println(String.format("start-test:%s", getId(test)));
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void endTest(Test test) {
+            System.out.println(String.format("end-test:%s", getId(test)));
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void addFailure(Test test, AssertionFailedError error) {
+            System.out.println(String.format("failure:%s", stringify(error)));
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void addError(Test test, Throwable error) {
+            System.out.println(String.format("failure:%s", stringify(error)));
+        }
+
+        private String getId(Test test) {
+            String className = test.getClass().getName();
+            if (test instanceof TestCase) {
+                return String.format("%s#%s", className, ((TestCase) test).getName());
+            }
+            return className;
+        }
+
+        private String stringify(Throwable error) {
+            return Arrays.toString(error.getStackTrace()).replaceAll("\n", " ");
+        }
+    }
+}
diff --git a/tests/libcore/runner/host-side/Android.mk b/tests/libcore/runner/host-side/Android.mk
new file mode 100644
index 0000000..a0756cb
--- /dev/null
+++ b/tests/libcore/runner/host-side/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := cts-dalvik-host-test-runner
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 tradefed-prebuilt compatibility-host-util
+
+LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib
+
+# don't include these packages in any target
+LOCAL_MODULE_TAGS := optional
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/tests/libcore/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java b/tests/libcore/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java
new file mode 100644
index 0000000..4fc711c
--- /dev/null
+++ b/tests/libcore/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.testtype;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.ddmlib.IShellOutputReceiver;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.MultiLineReceiver;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.ITestFilterReceiver;
+import com.android.tradefed.util.ArrayUtil;
+
+import vogar.ExpectationStore;
+import vogar.ModeId;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A wrapper to run tests against Dalvik.
+ */
+public class DalvikTest implements IAbiReceiver, IBuildReceiver, IDeviceTest, IRemoteTest,
+        ITestFilterReceiver {
+
+    private static final String TAG = DalvikTest.class.getSimpleName();
+
+    // Command to run the VM, args are bitness, classpath, dalvik-args, abi, runner-args,
+    // include and exclude filters, and exclude filters file.
+    private static final String COMMAND = "dalvikvm%s -classpath %s %s "
+            + "com.android.compatibility.dalvik.DalvikTestRunner --abi=%s %s %s %s %s %s";
+    private static final String INCLUDE_FILE = "/data/local/tmp/ctslibcore/includes";
+    private static final String EXCLUDE_FILE = "/data/local/tmp/ctslibcore/excludes";
+    private static String START_RUN = "start-run";
+    private static String END_RUN = "end-run";
+    private static String START_TEST = "start-test";
+    private static String END_TEST = "end-test";
+    private static String FAILURE = "failure";
+
+    @Option(name = "run-name", description = "The name to use when reporting results")
+    private String mRunName;
+
+    @Option(name = "expectations", description = "The names of the expectation files")
+    private Set<String> mExpectations = new HashSet<>();
+
+    @Option(name = "classpath", description = "Holds the paths to search when loading tests")
+    private List<String> mClasspath = new ArrayList<>();
+
+    @Option(name = "dalvik-arg", description = "Holds arguments to pass to Dalvik")
+    private List<String> mDalvikArgs = new ArrayList<>();
+
+    @Option(name = "runner-arg",
+            description = "Holds arguments to pass to the device-side test runner")
+    private List<String> mRunnerArgs = new ArrayList<>();
+
+    @Option(name = "include-filter",
+            description = "The include filters of the test name to run.")
+    private List<String> mIncludeFilters = new ArrayList<>();
+
+    @Option(name = "exclude-filter",
+            description = "The exclude filters of the test name to run.")
+    private List<String> mExcludeFilters = new ArrayList<>();
+
+    private IAbi mAbi;
+    private CompatibilityBuildHelper mBuildHelper;
+    private ITestDevice mDevice;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo build) {
+        mBuildHelper = new CompatibilityBuildHelper(build);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDevice(ITestDevice device) {
+        mDevice = device;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ITestDevice getDevice() {
+        return mDevice;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addIncludeFilter(String filter) {
+        mIncludeFilters.add(filter);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addAllIncludeFilters(List<String> filters) {
+        mIncludeFilters.addAll(filters);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addExcludeFilter(String filter) {
+        mExcludeFilters.add(filter);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addAllExcludeFilters(List<String> filters) {
+        mExcludeFilters.addAll(filters);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void run(final ITestInvocationListener listener) throws DeviceNotAvailableException {
+        String abiName = mAbi.getName();
+        String bitness = AbiUtils.getBitness(abiName);
+
+        File temp = null;
+        PrintWriter out = null;
+        try {
+            Set<File> expectationFiles = new HashSet<>();
+            for (String file : mExpectations) {
+                expectationFiles.add(new File(mBuildHelper.getTestsDir(), file));
+            }
+            ExpectationStore store = ExpectationStore.parse(expectationFiles, ModeId.DEVICE);
+
+            // Work around because there are to many expectations to pass via command line
+            temp = File.createTempFile("excludes", "txt");
+            out = new PrintWriter(temp);
+            for (String exclude : store.getAllFailures().keySet()) {
+                out.println(exclude);
+            }
+            for (String exclude : store.getAllOutComes().keySet()) {
+                out.println(exclude);
+            }
+            out.flush();
+            if (!mDevice.pushFile(temp, EXCLUDE_FILE)) {
+                Log.logAndDisplay(LogLevel.ERROR, TAG, "Couldn't push file: " + temp);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (out != null) {
+                out.close();
+            }
+            temp.delete();
+        }
+
+        // Create command
+        String dalvikArgs = ArrayUtil.join(" ", mDalvikArgs);
+        String runnerArgs = ArrayUtil.join(" ", mRunnerArgs);
+        // Filters
+        StringBuilder includeFilters = new StringBuilder();
+        if (!mIncludeFilters.isEmpty()) {
+            includeFilters.append("--include-filter=");
+            includeFilters.append(ArrayUtil.join(",", mIncludeFilters));
+        }
+        StringBuilder excludeFilters = new StringBuilder();
+        if (!mExcludeFilters.isEmpty()) {
+            excludeFilters.append("--exclude-filter=");
+            excludeFilters.append(ArrayUtil.join(",", mExcludeFilters));
+        }
+        // Filter files
+        String includeFile = ""; // String.format("--include-filter-file=%s", INCLUDE);
+        String excludeFile = String.format("--exclude-filter-file=%s", EXCLUDE_FILE);
+        String command = String.format(COMMAND, bitness,
+                ArrayUtil.join(File.pathSeparator, mClasspath),
+                dalvikArgs, abiName, runnerArgs,
+                includeFilters, excludeFilters, includeFile, excludeFile);
+        IShellOutputReceiver receiver = new MultiLineReceiver() {
+            private TestIdentifier test;
+
+            @Override
+            public boolean isCancelled() {
+                return false;
+            }
+
+            @Override
+            public void processNewLines(String[] lines) {
+                for (String line : lines) {
+                    String[] parts = line.split(":");
+                    String tag = parts[0];
+                    if (tag.equals(START_RUN)) {
+                        listener.testRunStarted(mRunName, Integer.parseInt(parts[1]));
+                    } else if (tag.equals(END_RUN)) {
+                        listener.testRunEnded(Integer.parseInt(parts[1]),
+                                new HashMap<String, String>());
+                    } else if (tag.equals(START_TEST)) {
+                        test = getTestIdentifier(parts[1]);
+                        listener.testStarted(test);
+                    } else if (tag.equals(FAILURE)) {
+                        listener.testFailed(test, parts[1]);
+                    } else if (tag.equals(END_TEST)) {
+                        listener.testEnded(getTestIdentifier(parts[1]),
+                                new HashMap<String, String>());
+                    } else {
+                        Log.logAndDisplay(LogLevel.INFO, TAG, line);
+                    }
+                }
+            }
+
+            private TestIdentifier getTestIdentifier(String name) {
+                String[] parts = name.split("#");
+                String className = parts[0];
+                String testName = "";
+                if (parts.length > 1) {
+                    testName = parts[1];
+                }
+                return new TestIdentifier(className, testName);
+            }
+
+        };
+        mDevice.executeShellCommand(command, receiver, 1, TimeUnit.HOURS, 1);
+    }
+
+}
diff --git a/tests/netlegacy22.api/Android.mk b/tests/netlegacy22.api/Android.mk
index 68fd6f8..c08a5a8 100644
--- a/tests/netlegacy22.api/Android.mk
+++ b/tests/netlegacy22.api/Android.mk
@@ -29,4 +29,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/netlegacy22.api/AndroidManifest.xml b/tests/netlegacy22.api/AndroidManifest.xml
index f13805c..e900ceb 100644
--- a/tests/netlegacy22.api/AndroidManifest.xml
+++ b/tests/netlegacy22.api/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.netlegacy22.api">
+    package="android.netlegacy22.api.cts">
 
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -30,7 +30,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.netlegacy22.api"
+                     android:targetPackage="android.netlegacy22.api.cts"
                      android:label="CTS tests of legacy android.net APIs as of API 22">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/netlegacy22.api/AndroidTest.xml b/tests/netlegacy22.api/AndroidTest.xml
new file mode 100644
index 0000000..b40f21a
--- /dev/null
+++ b/tests/netlegacy22.api/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Legacy android.net APIs test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsNetTestCasesLegacyApi22.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.netlegacy22.api.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/netlegacy22.permission/Android.mk b/tests/netlegacy22.permission/Android.mk
index fff9d85..37a7cde 100644
--- a/tests/netlegacy22.permission/Android.mk
+++ b/tests/netlegacy22.permission/Android.mk
@@ -29,4 +29,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/netlegacy22.permission/AndroidManifest.xml b/tests/netlegacy22.permission/AndroidManifest.xml
index cd1d2ba..af22b47 100644
--- a/tests/netlegacy22.permission/AndroidManifest.xml
+++ b/tests/netlegacy22.permission/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.netlegacy22.permission">
+    package="android.netlegacy22.permission.cts">
 
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <application>
@@ -41,7 +41,7 @@
         relies on hidden APIs.
     -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.netlegacy22.permission"
+                     android:targetPackage="android.netlegacy22.permission.cts"
                      android:label="CTS tests of legacy android.net permissions as of API 22">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/netlegacy22.permission/AndroidTest.xml b/tests/netlegacy22.permission/AndroidTest.xml
new file mode 100644
index 0000000..490e979
--- /dev/null
+++ b/tests/netlegacy22.permission/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Legacy android.net Permission test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsNetTestCasesLegacyPermission22.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.netlegacy22.permission.cts" />
+    </test>
+</configuration>
diff --git a/tests/openglperf2/Android.mk b/tests/openglperf2/Android.mk
new file mode 100644
index 0000000..a0488c2
--- /dev/null
+++ b/tests/openglperf2/Android.mk
@@ -0,0 +1,39 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+
+# Include both the 32 and 64 bit versions
+LOCAL_MULTILIB := both
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+
+LOCAL_JNI_SHARED_LIBRARIES := libctsopengl_jni
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsOpenGlPerf2TestCases
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := 16
+
+include $(BUILD_CTS_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/openglperf2/AndroidManifest.xml b/tests/openglperf2/AndroidManifest.xml
new file mode 100644
index 0000000..b1051a4d
--- /dev/null
+++ b/tests/openglperf2/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.opengl2.cts"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="16"
+        android:targetSdkVersion="17" />
+
+    <uses-feature
+        android:glEsVersion="0x00020000"
+        android:required="true" />
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+
+    <application android:allowBackup="false" >
+        <uses-library android:name="android.test.runner" />
+
+        <activity
+            android:name=".primitive.GLPrimitiveActivity"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".reference.GLReferenceActivity"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".reference.GLGameActivity"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
+        </activity>
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:label="OpenGL ES Benchmark"
+        android:targetPackage="android.opengl2.cts" />
+
+</manifest>
\ No newline at end of file
diff --git a/tests/openglperf2/AndroidTest.xml b/tests/openglperf2/AndroidTest.xml
new file mode 100644
index 0000000..b4ca796
--- /dev/null
+++ b/tests/openglperf2/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS OpenGL test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsOpenGlPerf2TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.opengl2.cts" />
+        <option name="runtime-hint" value="4m" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/suite/cts/deviceTests/opengl/README b/tests/openglperf2/README
similarity index 100%
rename from suite/cts/deviceTests/opengl/README
rename to tests/openglperf2/README
diff --git a/suite/cts/deviceTests/opengl/assets/fragment/basic b/tests/openglperf2/assets/fragment/basic
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/fragment/basic
rename to tests/openglperf2/assets/fragment/basic
diff --git a/suite/cts/deviceTests/opengl/assets/fragment/blur b/tests/openglperf2/assets/fragment/blur
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/fragment/blur
rename to tests/openglperf2/assets/fragment/blur
diff --git a/suite/cts/deviceTests/opengl/assets/fragment/perspective b/tests/openglperf2/assets/fragment/perspective
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/fragment/perspective
rename to tests/openglperf2/assets/fragment/perspective
diff --git a/suite/cts/deviceTests/opengl/assets/fragment/water b/tests/openglperf2/assets/fragment/water
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/fragment/water
rename to tests/openglperf2/assets/fragment/water
diff --git a/suite/cts/deviceTests/opengl/assets/mesh/arc.cob b/tests/openglperf2/assets/mesh/arc.cob
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/mesh/arc.cob
rename to tests/openglperf2/assets/mesh/arc.cob
Binary files differ
diff --git a/suite/cts/deviceTests/opengl/assets/mesh/fish.cob b/tests/openglperf2/assets/mesh/fish.cob
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/mesh/fish.cob
rename to tests/openglperf2/assets/mesh/fish.cob
Binary files differ
diff --git a/suite/cts/deviceTests/opengl/assets/mesh/plane.cob b/tests/openglperf2/assets/mesh/plane.cob
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/mesh/plane.cob
rename to tests/openglperf2/assets/mesh/plane.cob
Binary files differ
diff --git a/suite/cts/deviceTests/opengl/assets/texture/arc.png b/tests/openglperf2/assets/texture/arc.png
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/texture/arc.png
rename to tests/openglperf2/assets/texture/arc.png
Binary files differ
diff --git a/suite/cts/deviceTests/opengl/assets/texture/background.png b/tests/openglperf2/assets/texture/background.png
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/texture/background.png
rename to tests/openglperf2/assets/texture/background.png
Binary files differ
diff --git a/suite/cts/deviceTests/opengl/assets/texture/fish.png b/tests/openglperf2/assets/texture/fish.png
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/texture/fish.png
rename to tests/openglperf2/assets/texture/fish.png
Binary files differ
diff --git a/suite/cts/deviceTests/opengl/assets/texture/fish_dark.png b/tests/openglperf2/assets/texture/fish_dark.png
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/texture/fish_dark.png
rename to tests/openglperf2/assets/texture/fish_dark.png
Binary files differ
diff --git a/suite/cts/deviceTests/opengl/assets/texture/water1.png b/tests/openglperf2/assets/texture/water1.png
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/texture/water1.png
rename to tests/openglperf2/assets/texture/water1.png
Binary files differ
diff --git a/suite/cts/deviceTests/opengl/assets/texture/water2.png b/tests/openglperf2/assets/texture/water2.png
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/texture/water2.png
rename to tests/openglperf2/assets/texture/water2.png
Binary files differ
diff --git a/suite/cts/deviceTests/opengl/assets/vertex/basic b/tests/openglperf2/assets/vertex/basic
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/vertex/basic
rename to tests/openglperf2/assets/vertex/basic
diff --git a/suite/cts/deviceTests/opengl/assets/vertex/blur b/tests/openglperf2/assets/vertex/blur
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/vertex/blur
rename to tests/openglperf2/assets/vertex/blur
diff --git a/suite/cts/deviceTests/opengl/assets/vertex/perspective b/tests/openglperf2/assets/vertex/perspective
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/vertex/perspective
rename to tests/openglperf2/assets/vertex/perspective
diff --git a/suite/cts/deviceTests/opengl/assets/vertex/water b/tests/openglperf2/assets/vertex/water
similarity index 100%
rename from suite/cts/deviceTests/opengl/assets/vertex/water
rename to tests/openglperf2/assets/vertex/water
diff --git a/suite/cts/deviceTests/opengl/cob_exporter.py b/tests/openglperf2/cob_exporter.py
similarity index 100%
rename from suite/cts/deviceTests/opengl/cob_exporter.py
rename to tests/openglperf2/cob_exporter.py
diff --git a/suite/cts/deviceTests/opengl/jni/Android.mk b/tests/openglperf2/jni/Android.mk
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/Android.mk
rename to tests/openglperf2/jni/Android.mk
diff --git a/suite/cts/deviceTests/opengl/jni/Trace.h b/tests/openglperf2/jni/Trace.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/Trace.h
rename to tests/openglperf2/jni/Trace.h
diff --git a/tests/openglperf2/jni/graphics/GLUtils.cpp b/tests/openglperf2/jni/graphics/GLUtils.cpp
new file mode 100644
index 0000000..7786447
--- /dev/null
+++ b/tests/openglperf2/jni/graphics/GLUtils.cpp
@@ -0,0 +1,237 @@
+/*
+ * 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.
+ */
+
+#include "GLUtils.h"
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <android/asset_manager_jni.h>
+
+#define LOG_TAG "CTS_OPENGL"
+#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+static JNIEnv* sEnv = NULL;
+static jobject sAssetManager = NULL;
+
+void GLUtils::setEnvAndAssetManager(JNIEnv* env, jobject assetManager) {
+    sEnv = env;
+    sAssetManager = assetManager;
+}
+
+static AAsset* loadAsset(const char* path) {
+    AAssetManager* nativeManager = AAssetManager_fromJava(sEnv, sAssetManager);
+    if (nativeManager == NULL) {
+        return NULL;
+    }
+    return AAssetManager_open(nativeManager, path, AASSET_MODE_UNKNOWN);;
+}
+
+char* GLUtils::openTextFile(const char* path) {
+    AAsset* asset = loadAsset(path);
+    if (asset == NULL) {
+        ALOGE("Couldn't load %s", path);
+        return NULL;
+    }
+    off_t length = AAsset_getLength(asset);
+    char* buffer = new char[length + 1];
+    int num = AAsset_read(asset, buffer, length);
+    AAsset_close(asset);
+    if (num != length) {
+        ALOGE("Couldn't read %s", path);
+        delete[] buffer;
+        return NULL;
+    }
+    buffer[length] = '\0';
+    return buffer;
+}
+
+GLuint GLUtils::loadTexture(const char* path) {
+    GLuint textureId = 0;
+    jclass activityClass = sEnv->FindClass("android/opengl2/cts/reference/GLGameActivity");
+    if (activityClass == NULL) {
+        ALOGE("Couldn't find activity class");
+        return -1;
+    }
+    jmethodID loadTexture = sEnv->GetStaticMethodID(activityClass, "loadTexture",
+            "(Landroid/content/res/AssetManager;Ljava/lang/String;)I");
+    if (loadTexture == NULL) {
+        ALOGE("Couldn't find loadTexture method");
+        return -1;
+    }
+    jstring pathStr = sEnv->NewStringUTF(path);
+    textureId = sEnv->CallStaticIntMethod(activityClass, loadTexture, sAssetManager, pathStr);
+    sEnv->DeleteLocalRef(pathStr);
+    return textureId;
+}
+
+static int readInt(char* b) {
+    unsigned char* ub = (unsigned char*) b;
+    return (((int) ub[0]) << 24) | (((int) ub[1]) << 16) | (((int) ub[2]) << 8) | ((int) ub[3]);
+}
+
+static float readFloat(char* b) {
+    union {
+        int input;
+        float output;
+    } data;
+    data.input = readInt(b);
+    return data.output;
+}
+
+Mesh* GLUtils::loadMesh(const char* path) {
+    char* buffer = openTextFile(path);
+    if (buffer == NULL) {
+        return NULL;
+    }
+    int index = 0;
+    int numVertices = readInt(buffer + index);
+    index += 4;
+    float* vertices = new float[numVertices * 3];
+    float* normals = new float[numVertices * 3];
+    float* texCoords = new float[numVertices * 2];
+    for (int i = 0; i < numVertices; i++) {
+        // Vertices
+        int vIndex = i * 3;
+        vertices[vIndex + 0] = readFloat(buffer + index);
+        index += 4;
+        vertices[vIndex + 1] = readFloat(buffer + index);
+        index += 4;
+        vertices[vIndex + 2] = readFloat(buffer + index);
+        index += 4;
+        // Normals
+        normals[vIndex + 0] = readFloat(buffer + index);
+        index += 4;
+        normals[vIndex + 1] = readFloat(buffer + index);
+        index += 4;
+        normals[vIndex + 2] = readFloat(buffer + index);
+        index += 4;
+        // Texture Coordinates
+        int tIndex = i * 2;
+        texCoords[tIndex + 0] = readFloat(buffer + index);
+        index += 4;
+        texCoords[tIndex + 1] = readFloat(buffer + index);
+        index += 4;
+    }
+    return new Mesh(vertices, normals, texCoords, numVertices);
+}
+
+// Loads the given source code as a shader of the given type.
+static GLuint loadShader(GLenum shaderType, const char** source) {
+    GLuint shader = glCreateShader(shaderType);
+    if (shader) {
+        glShaderSource(shader, 1, source, NULL);
+        glCompileShader(shader);
+        GLint compiled = 0;
+        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+        if (!compiled) {
+            GLint infoLen = 0;
+            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen > 0) {
+                char* infoLog = (char*) malloc(sizeof(char) * infoLen);
+                glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
+                ALOGE("Error compiling shader:\n%s\n", infoLog);
+                free(infoLog);
+            }
+            glDeleteShader(shader);
+            shader = 0;
+        }
+    }
+    return shader;
+}
+
+GLuint GLUtils::createProgram(const char** vertexSource, const char** fragmentSource) {
+    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource);
+    if (!vertexShader) {
+        return 0;
+    }
+
+    GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
+    if (!fragmentShader) {
+        return 0;
+    }
+
+    GLuint program = glCreateProgram();
+    if (program) {
+        glAttachShader(program, vertexShader);
+        glAttachShader(program, fragmentShader);
+
+        GLint linkStatus;
+        glLinkProgram(program);
+        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+
+        if (!linkStatus) {
+            GLint infoLen = 0;
+            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen > 0) {
+                char* infoLog = (char*) malloc(sizeof(char) * infoLen);
+                glGetProgramInfoLog(program, infoLen, NULL, infoLog);
+                ALOGE("Error linking program:\n%s\n", infoLog);
+                free(infoLog);
+            }
+            glDeleteProgram(program);
+            program = 0;
+        }
+    }
+    return program;
+}
+
+double GLUtils::currentTimeMillis() {
+    struct timeval tv;
+    gettimeofday(&tv, (struct timezone *) NULL);
+    return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
+}
+
+// Rounds a number up to the smallest power of 2 that is greater than or equal to x.
+int GLUtils::roundUpToSmallestPowerOf2(int x) {
+    if (x < 0) {
+        return 0;
+    }
+    --x;
+    x |= x >> 1;
+    x |= x >> 2;
+    x |= x >> 4;
+    x |= x >> 8;
+    x |= x >> 16;
+    return x + 1;
+}
+
+GLuint GLUtils::genTexture(int texWidth, int texHeight, int fill) {
+    GLuint textureId = 0;
+    int w = roundUpToSmallestPowerOf2(texWidth);
+    int h = roundUpToSmallestPowerOf2(texHeight);
+    uint32_t* m = new uint32_t[w * h];
+    if (m != NULL) {
+        uint32_t* d = m;
+        for (int y = 0; y < h; y++) {
+            for (int x = 0; x < w; x++) {
+                if (fill == RANDOM_FILL) {
+                    *d = 0xff000000 | ((y & 0xff) << 16) | ((x & 0xff) << 8) | ((x + y) & 0xff);
+                } else {
+                    *d = 0xff000000 | fill;
+                }
+                d++;
+            }
+        }
+        glGenTextures(1, &textureId);
+        glBindTexture(GL_TEXTURE_2D, textureId);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    }
+    delete[] m;
+    return textureId;
+}
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/GLUtils.h b/tests/openglperf2/jni/graphics/GLUtils.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/GLUtils.h
rename to tests/openglperf2/jni/graphics/GLUtils.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Matrix.cpp b/tests/openglperf2/jni/graphics/Matrix.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/Matrix.cpp
rename to tests/openglperf2/jni/graphics/Matrix.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Matrix.h b/tests/openglperf2/jni/graphics/Matrix.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/Matrix.h
rename to tests/openglperf2/jni/graphics/Matrix.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Mesh.cpp b/tests/openglperf2/jni/graphics/Mesh.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/Mesh.cpp
rename to tests/openglperf2/jni/graphics/Mesh.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Mesh.h b/tests/openglperf2/jni/graphics/Mesh.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/Mesh.h
rename to tests/openglperf2/jni/graphics/Mesh.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/MeshNode.cpp b/tests/openglperf2/jni/graphics/MeshNode.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/MeshNode.cpp
rename to tests/openglperf2/jni/graphics/MeshNode.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/MeshNode.h b/tests/openglperf2/jni/graphics/MeshNode.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/MeshNode.h
rename to tests/openglperf2/jni/graphics/MeshNode.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/PerspectiveMeshNode.cpp b/tests/openglperf2/jni/graphics/PerspectiveMeshNode.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/PerspectiveMeshNode.cpp
rename to tests/openglperf2/jni/graphics/PerspectiveMeshNode.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/PerspectiveMeshNode.h b/tests/openglperf2/jni/graphics/PerspectiveMeshNode.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/PerspectiveMeshNode.h
rename to tests/openglperf2/jni/graphics/PerspectiveMeshNode.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/PerspectiveProgram.cpp b/tests/openglperf2/jni/graphics/PerspectiveProgram.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/PerspectiveProgram.cpp
rename to tests/openglperf2/jni/graphics/PerspectiveProgram.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/PerspectiveProgram.h b/tests/openglperf2/jni/graphics/PerspectiveProgram.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/PerspectiveProgram.h
rename to tests/openglperf2/jni/graphics/PerspectiveProgram.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Program.cpp b/tests/openglperf2/jni/graphics/Program.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/Program.cpp
rename to tests/openglperf2/jni/graphics/Program.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Program.h b/tests/openglperf2/jni/graphics/Program.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/Program.h
rename to tests/openglperf2/jni/graphics/Program.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/ProgramNode.cpp b/tests/openglperf2/jni/graphics/ProgramNode.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/ProgramNode.cpp
rename to tests/openglperf2/jni/graphics/ProgramNode.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/ProgramNode.h b/tests/openglperf2/jni/graphics/ProgramNode.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/ProgramNode.h
rename to tests/openglperf2/jni/graphics/ProgramNode.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Renderer.cpp b/tests/openglperf2/jni/graphics/Renderer.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/Renderer.cpp
rename to tests/openglperf2/jni/graphics/Renderer.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Renderer.h b/tests/openglperf2/jni/graphics/Renderer.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/Renderer.h
rename to tests/openglperf2/jni/graphics/Renderer.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/SceneGraphNode.cpp b/tests/openglperf2/jni/graphics/SceneGraphNode.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/SceneGraphNode.cpp
rename to tests/openglperf2/jni/graphics/SceneGraphNode.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/SceneGraphNode.h b/tests/openglperf2/jni/graphics/SceneGraphNode.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/SceneGraphNode.h
rename to tests/openglperf2/jni/graphics/SceneGraphNode.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/TexturedMeshNode.cpp b/tests/openglperf2/jni/graphics/TexturedMeshNode.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/TexturedMeshNode.cpp
rename to tests/openglperf2/jni/graphics/TexturedMeshNode.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/TexturedMeshNode.h b/tests/openglperf2/jni/graphics/TexturedMeshNode.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/TexturedMeshNode.h
rename to tests/openglperf2/jni/graphics/TexturedMeshNode.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/TransformationNode.cpp b/tests/openglperf2/jni/graphics/TransformationNode.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/TransformationNode.cpp
rename to tests/openglperf2/jni/graphics/TransformationNode.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/TransformationNode.h b/tests/openglperf2/jni/graphics/TransformationNode.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/TransformationNode.h
rename to tests/openglperf2/jni/graphics/TransformationNode.h
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Vector2D.cpp b/tests/openglperf2/jni/graphics/Vector2D.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/Vector2D.cpp
rename to tests/openglperf2/jni/graphics/Vector2D.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Vector2D.h b/tests/openglperf2/jni/graphics/Vector2D.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/graphics/Vector2D.h
rename to tests/openglperf2/jni/graphics/Vector2D.h
diff --git a/tests/openglperf2/jni/primitive/GLPrimitive.cpp b/tests/openglperf2/jni/primitive/GLPrimitive.cpp
new file mode 100644
index 0000000..825cadf
--- /dev/null
+++ b/tests/openglperf2/jni/primitive/GLPrimitive.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+#include <jni.h>
+
+#include <stdlib.h>
+
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+
+#include <graphics/GLUtils.h>
+#include <graphics/Renderer.h>
+
+#include "fullpipeline/FullPipelineRenderer.h"
+#include "pixeloutput/PixelOutputRenderer.h"
+#include "shaderperf/ShaderPerfRenderer.h"
+#include "contextswitch/ContextSwitchRenderer.h"
+
+// Holds the current benchmark's renderer.
+Renderer* gRenderer = NULL;
+ANativeWindow* gNativeWindow = NULL;
+
+enum {
+    FULL_PIPELINE_BENCHMARK = 0,
+    PIXEL_OUTPUT_BENCHMARK = 1,
+    SHADER_PERF_BENCHMARK = 2,
+    CONTEXT_SWITCH_BENCHMARK = 3
+};
+
+extern "C" JNIEXPORT jboolean JNICALL
+Java_android_opengl2_cts_primitive_GLPrimitiveActivity_startBenchmark(
+        JNIEnv* env, jclass /*clazz*/, jint workload, jint numFrames, jdoubleArray frameTimes) {
+    if (gRenderer == NULL) {
+        return false;
+    }
+
+    // Sets up the renderer.
+    bool success = gRenderer->setUp(workload);
+
+    // Records the start time.
+    double start = GLUtils::currentTimeMillis();
+
+    // Offscreen renders 100 tiles per frame so reduce the number of frames to render.
+    if (gRenderer->mOffscreen) {
+        numFrames /= Renderer::OFFSCREEN_INNER_FRAMES;
+    }
+
+    // Draw off the screen.
+    for (int i = 0; i < numFrames && success; i++) {
+        // Draw a frame.
+        success = gRenderer->draw();
+    }
+
+    // Records the end time.
+    double end = GLUtils::currentTimeMillis();
+
+    // Sets the times in the Java array.
+    double times[] = {start, end};
+    env->SetDoubleArrayRegion(frameTimes, 0, 2, times);
+
+    success = gRenderer->tearDown() && success;
+    return success;
+}
+
+// The following functions create the renderers for the various benchmarks.
+extern "C" JNIEXPORT void JNICALL
+Java_android_opengl2_cts_primitive_GLPrimitiveActivity_setupBenchmark(
+        JNIEnv* env, jclass /*clazz*/, jobject surface, jint benchmark,
+        jboolean offscreen) {
+    gNativeWindow = ANativeWindow_fromSurface(env, surface);
+    switch (benchmark) {
+        case FULL_PIPELINE_BENCHMARK:
+            gRenderer = new FullPipelineRenderer(gNativeWindow, offscreen);
+            break;
+        case PIXEL_OUTPUT_BENCHMARK:
+            gRenderer = new PixelOutputRenderer(gNativeWindow, offscreen);
+            break;
+        case SHADER_PERF_BENCHMARK:
+            gRenderer = new ShaderPerfRenderer(gNativeWindow, offscreen);
+            break;
+        case CONTEXT_SWITCH_BENCHMARK:
+            gRenderer = new ContextSwitchRenderer(gNativeWindow, offscreen);
+            break;
+        default:
+            ALOGE("Unknown benchmark '%d'", benchmark);
+            ANativeWindow_release(gNativeWindow);
+            gNativeWindow = NULL;
+            return;
+    }
+
+    // Set up call will log error conditions
+    if (!gRenderer->eglSetUp()) {
+        delete gRenderer;
+        gRenderer = NULL;
+
+        ANativeWindow_release(gNativeWindow);
+        gNativeWindow = NULL;
+    }
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_android_opengl2_cts_primitive_GLPrimitiveActivity_tearDownBenchmark(
+        JNIEnv* /*env*/, jclass /*clazz*/) {
+    if (gRenderer == NULL) {
+        return;
+    }
+    gRenderer->eglTearDown();
+    delete gRenderer;
+    gRenderer = NULL;
+
+    ANativeWindow_release(gNativeWindow);
+    gNativeWindow = NULL;
+}
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.cpp b/tests/openglperf2/jni/primitive/contextswitch/ContextSwitchRenderer.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.cpp
rename to tests/openglperf2/jni/primitive/contextswitch/ContextSwitchRenderer.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.h b/tests/openglperf2/jni/primitive/contextswitch/ContextSwitchRenderer.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.h
rename to tests/openglperf2/jni/primitive/contextswitch/ContextSwitchRenderer.h
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.cpp b/tests/openglperf2/jni/primitive/fullpipeline/FullPipelineRenderer.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.cpp
rename to tests/openglperf2/jni/primitive/fullpipeline/FullPipelineRenderer.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.h b/tests/openglperf2/jni/primitive/fullpipeline/FullPipelineRenderer.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.h
rename to tests/openglperf2/jni/primitive/fullpipeline/FullPipelineRenderer.h
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.cpp b/tests/openglperf2/jni/primitive/pixeloutput/PixelOutputRenderer.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.cpp
rename to tests/openglperf2/jni/primitive/pixeloutput/PixelOutputRenderer.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.h b/tests/openglperf2/jni/primitive/pixeloutput/PixelOutputRenderer.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.h
rename to tests/openglperf2/jni/primitive/pixeloutput/PixelOutputRenderer.h
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.cpp b/tests/openglperf2/jni/primitive/shaderperf/ShaderPerfRenderer.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.cpp
rename to tests/openglperf2/jni/primitive/shaderperf/ShaderPerfRenderer.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.h b/tests/openglperf2/jni/primitive/shaderperf/ShaderPerfRenderer.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.h
rename to tests/openglperf2/jni/primitive/shaderperf/ShaderPerfRenderer.h
diff --git a/tests/openglperf2/jni/reference/GLReference.cpp b/tests/openglperf2/jni/reference/GLReference.cpp
new file mode 100644
index 0000000..9af018a
--- /dev/null
+++ b/tests/openglperf2/jni/reference/GLReference.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+#include <jni.h>
+
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+
+#include <graphics/GLUtils.h>
+#include <graphics/Renderer.h>
+
+#include "ReferenceRenderer.h"
+
+extern "C" JNIEXPORT jboolean JNICALL
+Java_android_opengl2_cts_reference_GLGameActivity_startBenchmark(
+    JNIEnv* env, jclass /*clazz*/, jobject assetManager, jobject surface, jint numFrames,
+        jdoubleArray setUpTimes, jdoubleArray updateTimes, jdoubleArray renderTimes) {
+
+    GLUtils::setEnvAndAssetManager(env, assetManager);
+
+    if (numFrames > (ReferenceRenderer::FRAMES_PER_SCENE * ReferenceRenderer::NUM_SCENES)) {
+        return false;
+    }
+
+    ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface);
+    ReferenceRenderer* renderer = new ReferenceRenderer(nativeWindow);
+    bool success = renderer->eglSetUp();
+    success = renderer->setUp(0) && success;
+    env->SetDoubleArrayRegion(
+            setUpTimes, 0, ReferenceRenderer::NUM_SETUP_TIMES, renderer->mSetUpTimes);
+
+    double updates[numFrames];
+    double renders[numFrames];
+    for (int i = 0; i < numFrames && success; i++) {
+        double t0 = GLUtils::currentTimeMillis();
+        success = renderer->update(i);
+        double t1 = GLUtils::currentTimeMillis();
+        success = success && renderer->draw();
+        double t2 = GLUtils::currentTimeMillis();
+        updates[i] = t1 - t0;
+        renders[i] = t2 - t1;
+    }
+
+    env->SetDoubleArrayRegion(updateTimes, 0, numFrames, updates);
+    env->SetDoubleArrayRegion(renderTimes, 0, numFrames, renders);
+
+    success = renderer->tearDown() && success;
+    renderer->eglTearDown();
+    delete renderer;
+    renderer = NULL;
+
+    ANativeWindow_release(nativeWindow);
+
+    return success;
+}
diff --git a/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.cpp b/tests/openglperf2/jni/reference/ReferenceRenderer.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.cpp
rename to tests/openglperf2/jni/reference/ReferenceRenderer.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.h b/tests/openglperf2/jni/reference/ReferenceRenderer.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.h
rename to tests/openglperf2/jni/reference/ReferenceRenderer.h
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/Scene.cpp b/tests/openglperf2/jni/reference/scene/Scene.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/Scene.cpp
rename to tests/openglperf2/jni/reference/scene/Scene.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/Scene.h b/tests/openglperf2/jni/reference/scene/Scene.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/Scene.h
rename to tests/openglperf2/jni/reference/scene/Scene.h
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/flocking/Boid.cpp b/tests/openglperf2/jni/reference/scene/flocking/Boid.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/flocking/Boid.cpp
rename to tests/openglperf2/jni/reference/scene/flocking/Boid.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/flocking/Boid.h b/tests/openglperf2/jni/reference/scene/flocking/Boid.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/flocking/Boid.h
rename to tests/openglperf2/jni/reference/scene/flocking/Boid.h
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/flocking/FlockingScene.cpp b/tests/openglperf2/jni/reference/scene/flocking/FlockingScene.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/flocking/FlockingScene.cpp
rename to tests/openglperf2/jni/reference/scene/flocking/FlockingScene.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/flocking/FlockingScene.h b/tests/openglperf2/jni/reference/scene/flocking/FlockingScene.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/flocking/FlockingScene.h
rename to tests/openglperf2/jni/reference/scene/flocking/FlockingScene.h
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/flocking/WaterMeshNode.cpp b/tests/openglperf2/jni/reference/scene/flocking/WaterMeshNode.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/flocking/WaterMeshNode.cpp
rename to tests/openglperf2/jni/reference/scene/flocking/WaterMeshNode.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/flocking/WaterMeshNode.h b/tests/openglperf2/jni/reference/scene/flocking/WaterMeshNode.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/flocking/WaterMeshNode.h
rename to tests/openglperf2/jni/reference/scene/flocking/WaterMeshNode.h
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/glowing/BlurMeshNode.cpp b/tests/openglperf2/jni/reference/scene/glowing/BlurMeshNode.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/glowing/BlurMeshNode.cpp
rename to tests/openglperf2/jni/reference/scene/glowing/BlurMeshNode.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/glowing/BlurMeshNode.h b/tests/openglperf2/jni/reference/scene/glowing/BlurMeshNode.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/glowing/BlurMeshNode.h
rename to tests/openglperf2/jni/reference/scene/glowing/BlurMeshNode.h
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/glowing/GlowingScene.cpp b/tests/openglperf2/jni/reference/scene/glowing/GlowingScene.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/glowing/GlowingScene.cpp
rename to tests/openglperf2/jni/reference/scene/glowing/GlowingScene.cpp
diff --git a/suite/cts/deviceTests/opengl/jni/reference/scene/glowing/GlowingScene.h b/tests/openglperf2/jni/reference/scene/glowing/GlowingScene.h
similarity index 100%
rename from suite/cts/deviceTests/opengl/jni/reference/scene/glowing/GlowingScene.h
rename to tests/openglperf2/jni/reference/scene/glowing/GlowingScene.h
diff --git a/tests/openglperf2/src/android/opengl2/cts/GLActivityIntentKeys.java b/tests/openglperf2/src/android/opengl2/cts/GLActivityIntentKeys.java
new file mode 100644
index 0000000..fcd5f1a
--- /dev/null
+++ b/tests/openglperf2/src/android/opengl2/cts/GLActivityIntentKeys.java
@@ -0,0 +1,37 @@
+/*
+ * 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 android.opengl2.cts;
+
+public class GLActivityIntentKeys {
+    /**
+     * Holds the name of the benchmark to run.
+     */
+    public final static String INTENT_EXTRA_BENCHMARK_NAME = "benchmark_name";
+    /**
+     * Holds whether or not the benchmark is to be run offscreen.
+     */
+    public final static String INTENT_EXTRA_OFFSCREEN = "offscreen";
+    /**
+     * The number of frames to render for each workload.
+     */
+    public final static String INTENT_EXTRA_NUM_FRAMES = "num_frames";
+    /**
+     * The number of iterations to run, the workload increases with each iteration.
+     */
+    public final static String INTENT_EXTRA_NUM_ITERATIONS = "num_iterations";
+    /**
+     * The number of milliseconds to wait before timing out.
+     */
+    public final static String INTENT_EXTRA_TIMEOUT = "timeout";
+}
diff --git a/tests/openglperf2/src/android/opengl2/cts/primitive/BenchmarkName.java b/tests/openglperf2/src/android/opengl2/cts/primitive/BenchmarkName.java
new file mode 100644
index 0000000..02acfdc
--- /dev/null
+++ b/tests/openglperf2/src/android/opengl2/cts/primitive/BenchmarkName.java
@@ -0,0 +1,24 @@
+/*
+ * 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 android.opengl2.cts.primitive;
+
+/**
+ * Represents the different primitive benchmarks.
+ */
+public enum BenchmarkName {
+    FullPipeline,
+    PixelOutput,
+    ShaderPerf,
+    ContextSwitch;
+}
diff --git a/tests/openglperf2/src/android/opengl2/cts/primitive/GLPrimitiveActivity.java b/tests/openglperf2/src/android/opengl2/cts/primitive/GLPrimitiveActivity.java
new file mode 100644
index 0000000..6558786
--- /dev/null
+++ b/tests/openglperf2/src/android/opengl2/cts/primitive/GLPrimitiveActivity.java
@@ -0,0 +1,166 @@
+/*
+ * 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 android.opengl2.cts.primitive;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.cts.util.WatchDog;
+import android.opengl2.cts.GLActivityIntentKeys;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Semaphore;
+
+public class GLPrimitiveActivity extends Activity {
+
+    public final static String TAG = "GLPrimitiveActivity";
+
+    private volatile Exception mException;
+    private volatile Surface mSurface = null;
+    private CountDownLatch mStartSignal = new CountDownLatch(1);
+    private Semaphore mSemaphore = new Semaphore(0);
+
+    private BenchmarkName mBenchmark;
+    private boolean mOffscreen;
+    private int mNumFrames;
+    private int mNumIterations;
+    private int mTimeout;
+    public double[] mFpsValues;
+
+    @Override
+    public void onCreate(Bundle data) {
+        super.onCreate(data);
+        System.loadLibrary("ctsopengl_jni");
+        Intent intent = getIntent();
+        mBenchmark = BenchmarkName.valueOf(
+                intent.getStringExtra(GLActivityIntentKeys.INTENT_EXTRA_BENCHMARK_NAME));
+        mOffscreen = intent.getBooleanExtra(GLActivityIntentKeys.INTENT_EXTRA_OFFSCREEN, false);
+        mNumFrames = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, 0);
+        mNumIterations = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_ITERATIONS, 0);
+        mTimeout = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, 0);
+        mFpsValues = new double[mNumIterations];
+
+        Log.i(TAG, "Benchmark: " + mBenchmark);
+        Log.i(TAG, "Offscreen: " + mOffscreen);
+        Log.i(TAG, "Num Frames: " + mNumFrames);
+        Log.i(TAG, "Num Iterations: " + mNumIterations);
+        Log.i(TAG, "Time Out: " + mTimeout);
+
+        SurfaceView surfaceView = new SurfaceView(this);
+        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
+            @Override
+            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+                mSurface = holder.getSurface();
+                mStartSignal.countDown();
+            }
+
+            @Override
+            public void surfaceCreated(SurfaceHolder holder) {}
+
+            @Override
+            public void surfaceDestroyed(SurfaceHolder holder) {}
+        });
+        setContentView(surfaceView);
+        // Spawns a worker to run the benchmark.
+        Worker worker = new Worker();
+        worker.start();
+    }
+
+    public void waitForCompletion() throws Exception {
+        // Wait for semiphore.
+        mSemaphore.acquire();
+        if (mException != null) {
+            throw mException;
+        }
+    }
+
+    private void complete() {
+        // Release semiphore.
+        mSemaphore.release();
+        finish();
+    }
+
+    private synchronized void setException(Exception e) {
+        if (mException == null) {
+            mException = e;
+        }
+    }
+
+    private static native boolean setupBenchmark(
+            Surface surface, int benchmark, boolean offscreen);
+
+    private static native boolean startBenchmark(int workload, int numFrames, double[] frameTimes);
+
+    private static native void tearDownBenchmark();
+
+    /**
+     * This thread runs the benchmarks, freeing the UI thread.
+     */
+    private class Worker extends Thread implements WatchDog.TimeoutCallback {
+
+        private WatchDog watchDog;
+        private volatile boolean success = true;
+
+        @Override
+        public void run() {
+            try {
+                mStartSignal.await();
+            } catch (InterruptedException e) {
+                setException(e);
+                complete();
+                return;
+            }
+            Log.i(TAG, mBenchmark + " Benchmark Started");
+            // Creates a watchdog to ensure a iteration doesn't exceed the timeout.
+            watchDog = new WatchDog(mTimeout, this);
+            // Used to record the start and end time of the iteration.
+            double[] times = new double[2];
+            try {
+                // Setup the benchmark.
+                setupBenchmark(mSurface, mBenchmark.ordinal(), mOffscreen);
+                for (int i = 0; i < mNumIterations && success; i++) {
+                    // The workload to use for this iteration.
+                    int workload = i + 1;
+                    watchDog.start();
+                    // Start benchmark.
+                    success = startBenchmark(workload, mNumFrames, times);
+                    watchDog.stop();
+                    if (!success) {
+                        setException(new Exception("Benchmark failed to run"));
+                    } else {
+                        // Calculate FPS.
+                        mFpsValues[i] = mNumFrames * 1000.0f / (times[1] - times[0]);
+                    }
+                }
+            }
+            finally
+            {
+                tearDownBenchmark();
+            }
+
+            complete();
+            Log.i(TAG, mBenchmark + " Benchmark Completed");
+        }
+
+        public void onTimeout() {
+            setException(new Exception("Benchmark timed out"));
+            complete();
+        }
+
+    }
+}
diff --git a/tests/openglperf2/src/android/opengl2/cts/primitive/GLPrimitiveBenchmark.java b/tests/openglperf2/src/android/opengl2/cts/primitive/GLPrimitiveBenchmark.java
new file mode 100644
index 0000000..d737dbf
--- /dev/null
+++ b/tests/openglperf2/src/android/opengl2/cts/primitive/GLPrimitiveBenchmark.java
@@ -0,0 +1,140 @@
+/*
+ * 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 android.opengl2.cts.primitive;
+
+import android.content.Intent;
+import android.opengl2.cts.GLActivityIntentKeys;
+import android.test.ActivityInstrumentationTestCase2;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.cts.util.TimeoutReq;
+
+/**
+ * Runs the Primitive OpenGL ES 2.0 Benchmarks.
+ */
+public class GLPrimitiveBenchmark extends ActivityInstrumentationTestCase2<GLPrimitiveActivity> {
+
+    private static final int NUM_FRAMES = 100;
+    private static final int NUM_ITERATIONS = 8;
+    private static final int TIMEOUT = 1000000;
+
+    public GLPrimitiveBenchmark() {
+        super(GLPrimitiveActivity.class);
+    }
+
+    /**
+     * Runs the full OpenGL ES 2.0 pipeline test offscreen.
+     */
+    @TimeoutReq(minutes = 100)
+    public void testFullPipelineOffscreen() throws Exception {
+        runBenchmark(BenchmarkName.FullPipeline, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+    }
+
+    /**
+     * Runs the full OpenGL ES 2.0 pipeline test onscreen.
+     */
+    @TimeoutReq(minutes = 100)
+    public void testFullPipelineOnscreen() throws Exception {
+        runBenchmark(BenchmarkName.FullPipeline, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+    }
+
+    /**
+     * Runs the pixel output test offscreen.
+     */
+    @TimeoutReq(minutes = 100)
+    public void testPixelOutputOffscreen() throws Exception {
+        runBenchmark(BenchmarkName.PixelOutput, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+    }
+
+    /**
+     * Runs the pixel output test onscreen.
+     */
+    @TimeoutReq(minutes = 100)
+    public void testPixelOutputOnscreen() throws Exception {
+        runBenchmark(BenchmarkName.PixelOutput, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+    }
+
+    /**
+     * Runs the shader performance test offscreen.
+     */
+    @TimeoutReq(minutes = 100)
+    public void testShaderPerfOffscreen() throws Exception {
+        runBenchmark(BenchmarkName.ShaderPerf, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+    }
+
+    /**
+     * Runs the shader performance test onscreen.
+     */
+    @TimeoutReq(minutes = 100)
+    public void testShaderPerfOnscreen() throws Exception {
+        runBenchmark(BenchmarkName.ShaderPerf, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+    }
+
+    /**
+     * Runs the context switch overhead test offscreen.
+     */
+    @TimeoutReq(minutes = 100)
+    public void testContextSwitchOffscreen() throws Exception {
+        runBenchmark(BenchmarkName.ContextSwitch, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+    }
+
+    /**
+     * Runs the context switch overhead test onscreen.
+     */
+    @TimeoutReq(minutes = 100)
+    public void testContextSwitchOnscreen() throws Exception {
+        runBenchmark(BenchmarkName.ContextSwitch, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+    }
+
+    /**
+     * Runs the specified test.
+     *
+     * @param benchmark An enum representing the benchmark to run.
+     * @param offscreen Whether to render to an offscreen framebuffer rather than the screen.
+     * @param numFrames The number of frames to render.
+     * @param numIterations The number of iterations to run, each iteration has a bigger workload.
+     * @param timeout The milliseconds to wait for an iteration of the benchmark before timing out.
+     * @throws Exception If the benchmark could not be run.
+     */
+    private void runBenchmark(BenchmarkName benchmark, boolean offscreen, int numFrames,
+            int numIterations, int timeout) throws Exception {
+        String benchmarkName = benchmark.toString();
+        Intent intent = new Intent();
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_BENCHMARK_NAME, benchmarkName);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_OFFSCREEN, offscreen);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, numFrames);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_ITERATIONS, numIterations);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, timeout);
+
+        setActivityIntent(intent);
+        GLPrimitiveActivity activity = getActivity();
+        if (activity != null) {
+            activity.waitForCompletion();
+            double[] fpsValues = activity.mFpsValues;
+            double score = 0;
+            for (double d : fpsValues) {
+                score += d;
+            }
+            score /= numIterations;// Average.
+
+            // TODO: maybe standard deviation / RMSE will be useful?
+
+            DeviceReportLog report = new DeviceReportLog();
+            report.setSummary("Average FPS", score, ResultType.HIGHER_BETTER, ResultUnit.SCORE);
+            report.submit(getInstrumentation());
+        }
+    }
+}
diff --git a/tests/openglperf2/src/android/opengl2/cts/reference/GLGameActivity.java b/tests/openglperf2/src/android/opengl2/cts/reference/GLGameActivity.java
new file mode 100644
index 0000000..0bfb38b
--- /dev/null
+++ b/tests/openglperf2/src/android/opengl2/cts/reference/GLGameActivity.java
@@ -0,0 +1,181 @@
+/*
+ * 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 android.opengl2.cts.reference;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.AssetManager;
+import android.cts.util.WatchDog;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.opengl.GLES20;
+import android.opengl.GLUtils;
+import android.opengl2.cts.GLActivityIntentKeys;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.CountDownLatch;
+
+public class GLGameActivity extends Activity {
+
+    public final static String SET_UP_TIME = "set_up_time";
+    public final static String UPDATE_TIMES = "update_times";
+    public final static String RENDER_TIMES = "render_times";
+
+    private int mNumFrames;
+    private int mTimeout;
+    private double[] mSetUpTimes;
+    private double[] mUpdateTimes;
+    private double[] mRenderTimes;
+    private volatile Surface mSurface = null;
+    private CountDownLatch mStartSignal = new CountDownLatch(1);
+
+    @Override
+    public void onCreate(Bundle data) {
+        super.onCreate(data);
+        System.loadLibrary("ctsopengl_jni");
+
+        Intent intent = getIntent();
+        mNumFrames = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, 1000);
+        mTimeout = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, 1000000);
+
+        SurfaceView surfaceView = new SurfaceView(this);
+        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
+            @Override
+            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+                mSurface = holder.getSurface();
+                mStartSignal.countDown();
+            }
+
+            @Override
+            public void surfaceCreated(SurfaceHolder holder) {}
+
+            @Override
+            public void surfaceDestroyed(SurfaceHolder holder) {}
+        });
+        setContentView(surfaceView);
+
+        // Spawns a worker.
+        Worker worker = new Worker(new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                Intent intent = new Intent();
+                intent.putExtra(SET_UP_TIME, mSetUpTimes);
+                intent.putExtra(UPDATE_TIMES, mUpdateTimes);
+                intent.putExtra(RENDER_TIMES, mRenderTimes);
+                setResult((msg.what == 1) ? RESULT_OK : RESULT_CANCELED, intent);
+                finish();
+            }
+        });
+        worker.start();
+    }
+
+    private static native boolean startBenchmark(AssetManager manager,
+            Surface surface,
+            int numFrames,
+            double[] setUpTimes,
+            double[] updateTimes,
+            double[] renderTimes);
+
+    /**
+     * This thread renderers the benchmarks, freeing the UI thread.
+     */
+    private class Worker extends Thread implements WatchDog.TimeoutCallback {
+
+        private WatchDog watchDog;
+        private Handler mHandler;
+
+        public Worker(Handler handler) {
+            mHandler = handler;
+        }
+
+        @Override
+        public void run() {
+            try {
+                mStartSignal.await();
+            } catch (InterruptedException e) {
+                mHandler.sendEmptyMessage(0);
+                return;
+            }
+            // Creates a watchdog to ensure a iteration doesn't exceed the timeout.
+            watchDog = new WatchDog(mTimeout, this);
+            watchDog.start();
+
+            // Used to record the time taken to setup (GL, context, textures, meshes).
+            mSetUpTimes = new double[4];
+            // Used to record the times taken to update.
+            mUpdateTimes = new double[mNumFrames];
+            // Used to record the times taken to render.
+            mRenderTimes = new double[mNumFrames];
+            boolean success = startBenchmark(getAssets(),
+                    mSurface,
+                    mNumFrames,
+                    mSetUpTimes,
+                    mUpdateTimes,
+                    mRenderTimes);
+
+            watchDog.stop();
+            mHandler.sendEmptyMessage((success) ? 1 : 0);
+        }
+
+        @Override
+        public void onTimeout() {
+            mHandler.sendEmptyMessage(0);
+        }
+
+    }
+
+    public static int loadTexture(AssetManager manager, String path) {
+        InputStream in = null;
+        try {
+            in = manager.open(path);
+        } catch (IOException e) {
+            e.printStackTrace();
+            return -1;
+        }
+        BitmapFactory.Options op = new BitmapFactory.Options();
+        op.inPreferredConfig = Bitmap.Config.ARGB_8888;
+        Bitmap bmp = BitmapFactory.decodeStream(in, null, op);
+        // generate textureID
+        int[] textures = new int[1];
+        GLES20.glGenTextures(1, textures, 0);
+        int textureID = textures[0];
+
+        // create texture
+        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
+        GLES20.glTexParameteri(
+                GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
+        GLES20.glTexParameteri(
+                GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
+        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
+        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
+
+        // clean up
+        try {
+            in.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            bmp.recycle();
+        }
+        return textureID;
+    }
+}
diff --git a/tests/openglperf2/src/android/opengl2/cts/reference/GLReferenceActivity.java b/tests/openglperf2/src/android/opengl2/cts/reference/GLReferenceActivity.java
new file mode 100644
index 0000000..7a800a5
--- /dev/null
+++ b/tests/openglperf2/src/android/opengl2/cts/reference/GLReferenceActivity.java
@@ -0,0 +1,81 @@
+/*
+ * 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 android.opengl2.cts.reference;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.opengl2.cts.GLActivityIntentKeys;
+import android.os.Bundle;
+
+import java.util.concurrent.Semaphore;
+
+public class GLReferenceActivity extends Activity {
+
+    private final static int GAME_ACTIVITY_CODE = 1;
+
+    private volatile Exception mException;
+    private int mNumFrames;
+    private int mTimeout;
+
+    public double[] mSetUpTimes;
+    public double[] mUpdateTimes;
+    public double[] mRenderTimes;
+
+    private Semaphore mSemaphore = new Semaphore(0);
+
+    @Override
+    public void onCreate(Bundle data) {
+        super.onCreate(data);
+        Intent intent = getIntent();
+        mNumFrames = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, 0);
+        mTimeout = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, 0);
+
+        // Start benchmark
+        intent = new Intent(this, GLGameActivity.class);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, mNumFrames);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, mTimeout);
+        startActivityForResult(intent, GAME_ACTIVITY_CODE);
+    }
+
+    public void waitForCompletion() throws Exception {
+        // Wait for semiphore.
+        mSemaphore.acquire();
+        if (mException != null) {
+            throw mException;
+        }
+    }
+
+    private synchronized void setException(Exception e) {
+        if (mException == null) {
+            mException = e;
+        }
+    }
+
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == GAME_ACTIVITY_CODE) {
+            if (resultCode == RESULT_OK) {
+                // Benchmark passed
+                mSetUpTimes = data.getDoubleArrayExtra(GLGameActivity.SET_UP_TIME);
+                mUpdateTimes = data.getDoubleArrayExtra(GLGameActivity.UPDATE_TIMES);
+                mRenderTimes = data.getDoubleArrayExtra(GLGameActivity.RENDER_TIMES);
+            } else {
+                setException(new Exception("Benchmark failed to run"));
+            }
+            // Release semiphore.
+            mSemaphore.release();
+            finish();
+        }
+    }
+
+}
diff --git a/tests/openglperf2/src/android/opengl2/cts/reference/GLReferenceBenchmark.java b/tests/openglperf2/src/android/opengl2/cts/reference/GLReferenceBenchmark.java
new file mode 100644
index 0000000..196207c
--- /dev/null
+++ b/tests/openglperf2/src/android/opengl2/cts/reference/GLReferenceBenchmark.java
@@ -0,0 +1,81 @@
+/*
+ * 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 android.opengl2.cts.reference;
+
+import android.content.Intent;
+import android.opengl2.cts.GLActivityIntentKeys;
+import android.test.ActivityInstrumentationTestCase2;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.cts.util.TimeoutReq;
+
+/**
+ * Runs the Reference OpenGL ES 2.0 Benchmark.
+ */
+public class GLReferenceBenchmark extends ActivityInstrumentationTestCase2<GLReferenceActivity> {
+
+    private static final int NUM_FRAMES_PER_SCENE = 500;
+    private static final int NUM_SCENES = 2;
+    private static final int NUM_FRAMES = NUM_FRAMES_PER_SCENE * NUM_SCENES;
+    private static final int TIMEOUT = 1000000;
+
+    public GLReferenceBenchmark() {
+        super(GLReferenceActivity.class);
+    }
+
+    /**
+     * Runs the reference benchmark.
+     */
+    @TimeoutReq(minutes = 30)
+    public void testReferenceBenchmark() throws Exception {
+        Intent intent = new Intent();
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, NUM_FRAMES);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, TIMEOUT);
+
+        GLReferenceActivity activity = null;
+        setActivityIntent(intent);
+        activity = getActivity();
+        if (activity != null) {
+            activity.waitForCompletion();
+            double totalTime = 0;
+            double[] setUpTimes = activity.mSetUpTimes;
+            double[] updateTimes = activity.mUpdateTimes;
+            double[] renderTimes = activity.mRenderTimes;
+
+            // Calculate update and render average.
+            double updateSum = updateTimes[0];
+            double renderSum = renderTimes[0];
+            for (int i = 0; i < NUM_FRAMES - 1; i++) {
+                updateSum += updateTimes[i + 1];
+                renderSum += renderTimes[i + 1];
+            }
+            double updateAverage = updateSum / NUM_FRAMES;
+            double renderAverage = renderSum / NUM_FRAMES;
+
+            DeviceReportLog report = new DeviceReportLog();
+            report.addValues("Set Up Times", setUpTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+            report.addValue("Update Time Average", updateAverage, ResultType.LOWER_BETTER,
+                    ResultUnit.MS);
+            report.addValue("Render Time Average", renderAverage, ResultType.LOWER_BETTER,
+                    ResultUnit.MS);
+            totalTime = setUpTimes[0] + setUpTimes[1] + setUpTimes[2] + setUpTimes[3] +
+                    updateAverage + renderAverage;
+            report.setSummary("Total Time Average", totalTime, ResultType.LOWER_BETTER,
+                    ResultUnit.MS);
+            report.submit(getInstrumentation());
+        }
+    }
+}
diff --git a/suite/cts/deviceTests/opengl/test/Android.mk b/tests/openglperf2/test/Android.mk
similarity index 100%
rename from suite/cts/deviceTests/opengl/test/Android.mk
rename to tests/openglperf2/test/Android.mk
diff --git a/suite/cts/deviceTests/opengl/test/MatrixTest.cpp b/tests/openglperf2/test/MatrixTest.cpp
similarity index 100%
rename from suite/cts/deviceTests/opengl/test/MatrixTest.cpp
rename to tests/openglperf2/test/MatrixTest.cpp
diff --git a/tests/sample/Android.mk b/tests/sample/Android.mk
index 5e8f571..1255032 100755
--- a/tests/sample/Android.mk
+++ b/tests/sample/Android.mk
@@ -16,19 +16,24 @@
 
 include $(CLEAR_VARS)
 
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-# Must match the package name in CtsTestCaseList.mk
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_PACKAGE_NAME := CtsSampleDeviceTestCases
 
 LOCAL_SDK_VERSION := current
 
-include $(BUILD_CTS_PACKAGE)
+include $(BUILD_PACKAGE)
diff --git a/tests/sample/AndroidManifest.xml b/tests/sample/AndroidManifest.xml
index f07ebbe..2f32e86 100755
--- a/tests/sample/AndroidManifest.xml
+++ b/tests/sample/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.sample.cts">
 
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <application>
         <uses-library android:name="android.test.runner" />
         <activity android:name="android.sample.SampleDeviceActivity" >
@@ -34,9 +34,6 @@
         android:name="android.support.test.runner.AndroidJUnitRunner"
         android:label="CTS sample tests"
         android:targetPackage="android.sample.cts" >
-        <meta-data
-            android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
 </manifest>
 
diff --git a/tests/sample/AndroidTest.xml b/tests/sample/AndroidTest.xml
new file mode 100644
index 0000000..62b0d67
--- /dev/null
+++ b/tests/sample/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Sample test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSampleDeviceTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.sample.cts" />
+    </test>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="module-name" value="CtsSampleDeviceTestCases"/>
+        <option name="version-name" value="1.0"/>
+    </target_preparer>
+</configuration>
diff --git a/tests/sample/DynamicConfig.xml b/tests/sample/DynamicConfig.xml
new file mode 100644
index 0000000..18c07ef
--- /dev/null
+++ b/tests/sample/DynamicConfig.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<DynamicConfig>
+    <Config key ="local-config">local-config-val</Config>
+</DynamicConfig>
diff --git a/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java b/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
index 6bf883f..7bd434e 100644
--- a/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
+++ b/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
@@ -15,21 +15,25 @@
  */
 package android.sample.cts;
 
-import com.android.cts.util.MeasureRun;
-import com.android.cts.util.MeasureTime;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-import com.android.cts.util.Stat;
+import android.sample.SampleDeviceActivity;
+import android.test.ActivityInstrumentationTestCase2;
 
-import android.cts.util.CtsAndroidTestCase;
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.MeasureRun;
+import com.android.compatibility.common.util.MeasureTime;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+
+import java.util.Arrays;
+import java.util.Random;
 
 /**
  * A simple compatibility test which includes results in the report.
  *
  * This test measures the time taken to run a workload and adds in the report.
  */
-public class SampleDeviceResultTest extends CtsAndroidTestCase {
+public class SampleDeviceResultTest extends ActivityInstrumentationTestCase2<SampleDeviceActivity> {
 
     /**
      * The number of times to repeat the test.
@@ -37,86 +41,74 @@
     private static final int REPEAT = 5;
 
     /**
-     * The input number for the factorial.
+     * A {@link Random} to generate random integers to test the sort.
      */
-    private static final int IN = 15;
+    private static final Random random = new Random(12345);
 
     /**
-     * The expected output number for the factorial.
+     * Constructor which passes the class of the activity to be instrumented.
      */
-    private static final long OUT = 1307674368000L;
-
-    /**
-     * Measures the time taken to compute the factorial of 15 with a recursive method.
-     *
-     * @throws Exception
-     */
-    public void testFactorialRecursive() throws Exception {
-        runTest(new MeasureRun() {
-            @Override
-            public void run(int i) throws Exception {
-                // Compute the factorial and assert it is correct.
-                assertEquals("Incorrect result", OUT, factorialRecursive(IN));
-            }
-        });
+    public SampleDeviceResultTest() {
+        super(SampleDeviceActivity.class);
     }
 
     /**
-     * Measures the time taken to compute the factorial of 15 with a iterative method.
-     *
-     * @throws Exception
+     * Creates an array filled with random numbers of the given size.
      */
-    public void testFactorialIterative() throws Exception {
-        runTest(new MeasureRun() {
-            @Override
-            public void run(int i) throws Exception {
-                // Compute the factorial and assert it is correct.
-                assertEquals("Incorrect result", OUT, factorialIterative(IN));
-            }
-        });
-    }
-
-    /**
-     * Computes the factorial of a number with a recursive method.
-     *
-     * @param num The number to compute the factorial of.
-     */
-    private static long factorialRecursive(int num) {
-        if (num <= 0) {
-            return 1;
+    private static int[] createArray(int size) {
+        int[] array = new int[size];
+        for (int i = 0; i < size; i++) {
+            array[i] = random.nextInt();
         }
-        return num * factorialRecursive(num - 1);
+        return array;
     }
 
     /**
-     * Computes the factorial of a number with a iterative method.
-     *
-     * @param num The number to compute the factorial of.
+     * Tests an array is sorted.
      */
-    private static long factorialIterative(int num) {
-        long result = 1;
-        for (int i = 2; i <= num; i++) {
-            result *= i;
+    private static boolean isSorted(int[] array) {
+        int len = array.length;
+        for (int i = 0, j = 1; j < len; i++, j++) {
+            if (array[i] > array[j]) {
+                return false;
+            }
         }
-        return result;
+        return true;
     }
 
     /**
-     * Runs the workload and records the result to the report log.
-     *
-     * @param workload
+     * Measures the time taken to sort an array.
      */
-    private void runTest(MeasureRun workload) throws Exception {
+    public void testSort() throws Exception {
         // MeasureTime runs the workload N times and records the time taken by each run.
-        double[] result = MeasureTime.measure(REPEAT, workload);
+        double[] result = MeasureTime.measure(REPEAT, new MeasureRun() {
+            /**
+             * The size of the array to sort.
+             */
+            private static final int ARRAY_SIZE = 100000;
+            private int[] array;
+            @Override
+            public void prepare(int i) throws Exception {
+                array = createArray(ARRAY_SIZE);
+            }
+            @Override
+            public void run(int i) throws Exception {
+                Arrays.sort(array);
+                assertTrue("Array not sorted", isSorted(array));
+            }
+        });
         // Compute the stats.
         Stat.StatResult stat = Stat.getStat(result);
-        // Get the report for this test and add the results to record.
-        ReportLog log = getReportLog();
-        log.printArray("Times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue("Min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue("Max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
+        // Create a new report to hold the metrics.
+        DeviceReportLog reportLog = new DeviceReportLog();
+        // Add the results to the report.
+        reportLog.addValues("Times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
+        reportLog.addValue("Min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
+        reportLog.addValue("Max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
         // Every report must have a summary,
-        log.printSummary("Average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
+        reportLog.setSummary("Average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
+        // Submit the report to the given instrumentation.
+        reportLog.submit(getInstrumentation());
     }
+
 }
diff --git a/tests/sample/src/android/sample/cts/SampleDeviceTest.java b/tests/sample/src/android/sample/cts/SampleDeviceTest.java
index 13b7ea6..f51d227 100644
--- a/tests/sample/src/android/sample/cts/SampleDeviceTest.java
+++ b/tests/sample/src/android/sample/cts/SampleDeviceTest.java
@@ -18,6 +18,8 @@
 import android.sample.SampleDeviceActivity;
 import android.test.ActivityInstrumentationTestCase2;
 
+import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+
 /**
  * A simple compatibility test which tests the SharedPreferences API.
  *
@@ -73,4 +75,23 @@
         mActivity.clearPreferences();
         assertNull("Preferences were not cleared", mActivity.getPreference(KEY));
     }
+
+    /**
+     * Test if Dynamic Config on the device side works
+     * @throws Exception
+     */
+    public void testDynamicConfigLocal() throws Exception {
+        DynamicConfigDeviceSide config = new DynamicConfigDeviceSide("CtsSampleDeviceTestCases");
+        assertEquals("local-config-val", config.getConfig("local-config"));
+    }
+
+    /**
+     * Test if Dynamic Config override on the device side works
+     * @throws Exception
+     */
+    public void testDynamicConfigOverride() throws Exception {
+        DynamicConfigDeviceSide config = new DynamicConfigDeviceSide("CtsSampleDeviceTestCases");
+        assertEquals("device-1.0-cts-keyone", config.getConfig("sample_device_key_one"));
+
+    }
 }
diff --git a/tests/sample/src/android/sample/cts/SampleJUnit4DeviceTest.java b/tests/sample/src/android/sample/cts/SampleJUnit4DeviceTest.java
new file mode 100755
index 0000000..c8863b3
--- /dev/null
+++ b/tests/sample/src/android/sample/cts/SampleJUnit4DeviceTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 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.sample.cts;
+
+import org.junit.Assert;
+import org.junit.runner.RunWith;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import android.app.Activity;
+import android.sample.SampleDeviceActivity;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * A simple compatibility test which tests the SharedPreferences API.
+ *
+ * This test uses {@link ActivityTestRule} to instrument the
+ * {@link android.sample.SampleDeviceActivity}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class SampleJUnit4DeviceTest {
+
+    private static final String KEY = "foo";
+
+    private static final String VALUE = "bar";
+
+    @Rule
+    public ActivityTestRule<SampleDeviceActivity> mActivityRule =
+        new ActivityTestRule(SampleDeviceActivity.class);
+
+
+    /**
+     * This inserts the key value pair and assert they can be retrieved. Then it clears the
+     * preferences and asserts they can no longer be retrieved.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void shouldSaveSharedPreferences() throws Exception {
+        // Save the key value pair to the preferences and assert they were saved.
+        mActivityRule.getActivity().savePreference(KEY, VALUE);
+        Assert.assertEquals("Preferences were not saved", VALUE,
+            mActivityRule.getActivity().getPreference(KEY));
+
+        // Clear the shared preferences and assert the data was removed.
+        mActivityRule.getActivity().clearPreferences();
+        Assert.assertNull("Preferences were not cleared",
+            mActivityRule.getActivity().getPreference(KEY));
+    }
+}
diff --git a/tests/signature/Android.mk b/tests/signature/Android.mk
index 53ba50d..516f5ec 100644
--- a/tests/signature/Android.mk
+++ b/tests/signature/Android.mk
@@ -22,68 +22,18 @@
 
 LOCAL_PACKAGE_NAME := CtsSignatureTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+# For CTS v1
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
 LOCAL_SDK_VERSION := current
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
 
-# To be passed in on command line
-CTS_API_VERSION ?= current
-ifeq (current,$(CTS_API_VERSION))
-android_api_description := frameworks/base/api/$(CTS_API_VERSION).txt
-else
-android_api_description := $(SRC_API_DIR)/$(CTS_API_VERSION).txt
-endif
-
-# Can't call local-intermediates-dir directly here because we have to
-# include BUILD_CTS_PACKAGE first.  Can't include BUILD_CTS_PACKAGE first
-# because we have to override LOCAL_RESOURCE_DIR first.  Hence this
-# hack.
-intermediates.COMMON := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)
-signature_res_dir := $(intermediates.COMMON)/genres
-LOCAL_RESOURCE_DIR := $(signature_res_dir) $(LOCAL_PATH)/res
-
 include $(BUILD_CTS_PACKAGE)
 
-generated_res_stamp := $(intermediates.COMMON)/genres.stamp
-api_ver_file := $(intermediates.COMMON)/api_ver_is_$(CTS_API_VERSION)
-
-# The api_ver_file keeps track of which api version was last built.
-# By only ever having one of these magic files in existence and making
-# sure the generated resources rule depend on it, we can ensure that
-# the proper version of the api resource gets generated.
-$(api_ver_file):
-	$(hide) rm -f $(dir $@)/api_ver_is_* \
-		&& mkdir -p $(dir $@) && touch $@
-
-android_api_xml_description := $(intermediates.COMMON)/api.xml
-$(android_api_xml_description): $(android_api_description) | $(APICHECK)
-	@ echo "Convert api file to xml: $@"
-	@ mkdir -p $(dir $@)
-	$(hide) $(APICHECK_COMMAND) -convert2xml $< $@
-
-# Split up config/api/1.xml by "package" and save the files as the
-# resource files of SignatureTest.
-$(generated_res_stamp): PRIVATE_PATH := $(LOCAL_PATH)
-$(generated_res_stamp): PRIVATE_MODULE := $(LOCAL_MODULE)
-$(generated_res_stamp): PRIVATE_RES_DIR := $(signature_res_dir)
-$(generated_res_stamp): PRIVATE_API_XML_DESC := $(android_api_xml_description)
-$(generated_res_stamp): $(api_ver_file)
-$(generated_res_stamp): $(android_api_xml_description)
-	@ echo "Copy generated resources: $(PRIVATE_MODULE)"
-	$(hide) python cts/tools/utils/android_api_description_splitter.py \
-		$(PRIVATE_API_XML_DESC) $(PRIVATE_RES_DIR) package
-	$(hide) touch $@
-
-$(R_file_stamp): $(generated_res_stamp)
-
-# clean up temp vars
-android_api_xml_description :=
-api_ver_file :=
-generated_res_stamp :=
-signature_res_dir :=
-android_api_description :=
-CTS_API_VERSION :=
-
 # signature-hostside java library (for testing)
 # ============================================================
 
@@ -98,4 +48,6 @@
 
 LOCAL_MODULE_TAGS := optional
 
-include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/AndroidManifest.xml
index e42302e..52090ce 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.signature">
+          package="android.signature.cts">
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
     <application>
@@ -24,7 +24,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.signature"
+                     android:targetPackage="android.signature.cts"
                      android:label="API Signature Test"/>
 
 </manifest>
\ No newline at end of file
diff --git a/tests/signature/AndroidTest.xml b/tests/signature/AndroidTest.xml
new file mode 100644
index 0000000..e3561cc
--- /dev/null
+++ b/tests/signature/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Signature test cases">
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSignatureTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.signature.cts" />
+        <option name="runtime-hint" value="1m11s" />
+    </test>
+</configuration>
diff --git a/tests/signature/OldAndroidTest.xml b/tests/signature/OldAndroidTest.xml
new file mode 100644
index 0000000..b4338da
--- /dev/null
+++ b/tests/signature/OldAndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Signature test cases">
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
+    </target_preparer>
+    <target_preparer class="com.android.cts.tradefed.targetprep.CtsFilePusher">
+        <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
+    </target_preparer>
+</configuration>
diff --git a/tests/signature/api/Android.mk b/tests/signature/api/Android.mk
new file mode 100644
index 0000000..39a4337
--- /dev/null
+++ b/tests/signature/api/Android.mk
@@ -0,0 +1,42 @@
+# Copyright (C) 2015 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.
+
+# We define this in a subdir so that it won't pick up the parent's Android.xml by default.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# current api, in XML format.
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := cts-current-api
+LOCAL_MODULE_STEM := current.api
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_ETC)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE) : frameworks/base/api/current.txt | $(APICHECK)
+	@echo "Convert API file $@"
+	@mkdir -p $(dir $@)
+	$(hide) $(APICHECK_COMMAND) -convert2xml $< $@
+
+# For CTS v1
+cts_api_xml_v1 := $(CTS_TESTCASES_OUT)/current.api
+$(cts_api_xml_v1):  $(LOCAL_BUILT_MODULE) | $(ACP)
+	$(call copy-file-to-new-target)
+
+$(CTS_TESTCASES_OUT)/CtsSignatureTestCases.xml: $(cts_api_xml_v1)
diff --git a/tests/signature/src/android/signature/cts/SignatureTest.java b/tests/signature/src/android/signature/cts/SignatureTest.java
index 85b77f8..139fb30 100644
--- a/tests/signature/src/android/signature/cts/SignatureTest.java
+++ b/tests/signature/src/android/signature/cts/SignatureTest.java
@@ -17,7 +17,6 @@
 package android.signature.cts;
 
 import android.content.res.Resources;
-import android.signature.R;
 import android.signature.cts.JDiffClassDescription.JDiffConstructor;
 import android.signature.cts.JDiffClassDescription.JDiffField;
 import android.signature.cts.JDiffClassDescription.JDiffMethod;
@@ -26,13 +25,17 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
 
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Scanner;
 
 /**
  * Performs the signature check via a JUnit test.
@@ -40,6 +43,7 @@
 public class SignatureTest extends AndroidTestCase {
 
     private static final String TAG = SignatureTest.class.getSimpleName();
+    private static final String CURRENT_API_FILE = "/data/local/tmp/signature-test/current.api";
 
     private static final String TAG_ROOT = "api";
     private static final String TAG_PACKAGE = "package";
@@ -104,25 +108,21 @@
      * Will check the entire API, and then report the complete list of failures
      */
     public void testSignature() {
-        Resources r = getContext().getResources();
-        Class rClass = R.xml.class;
-        logd(String.format("Class: %s", rClass.toString()));
-        Field[] fs = rClass.getFields();
-        for (Field f : fs) {
-            logd(String.format("Field: %s", f.toString()));
-            try {
-                start(r.getXml(f.getInt(rClass)));
-            } catch (Exception e) {
-                mResultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION, e.getMessage(),
-                        e.getMessage());
-            }
+        try {
+            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+            XmlPullParser parser = factory.newPullParser();
+            parser.setInput(new FileInputStream(new File(CURRENT_API_FILE)), null);
+            start(parser);
+        } catch (Exception e) {
+            mResultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION, e.getMessage(),
+                    e.getMessage());
         }
         if (mResultObserver.mDidFail) {
             fail(mResultObserver.mErrorString.toString());
         }
     }
 
-    private  void beginDocument(XmlPullParser parser, String firstElementName)
+    private void beginDocument(XmlPullParser parser, String firstElementName)
             throws XmlPullParserException, IOException {
         int type;
         while ((type=parser.next()) != XmlPullParser.START_TAG
diff --git a/tests/signature-tests/Android.mk b/tests/signature/tests/Android.mk
similarity index 100%
rename from tests/signature-tests/Android.mk
rename to tests/signature/tests/Android.mk
diff --git a/tests/signature-tests/run_unit_tests.sh b/tests/signature/tests/run_unit_tests.sh
similarity index 100%
rename from tests/signature-tests/run_unit_tests.sh
rename to tests/signature/tests/run_unit_tests.sh
diff --git a/tests/signature-tests/src/android/signature/cts/tests/AllTests.java b/tests/signature/tests/src/android/signature/cts/tests/AllTests.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/AllTests.java
rename to tests/signature/tests/src/android/signature/cts/tests/AllTests.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java b/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
rename to tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/data/AbstractClass.java b/tests/signature/tests/src/android/signature/cts/tests/data/AbstractClass.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/data/AbstractClass.java
rename to tests/signature/tests/src/android/signature/cts/tests/data/AbstractClass.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/data/FinalClass.java b/tests/signature/tests/src/android/signature/cts/tests/data/FinalClass.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/data/FinalClass.java
rename to tests/signature/tests/src/android/signature/cts/tests/data/FinalClass.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/data/NormalClass.java b/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/data/NormalClass.java
rename to tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/data/NormalException.java b/tests/signature/tests/src/android/signature/cts/tests/data/NormalException.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/data/NormalException.java
rename to tests/signature/tests/src/android/signature/cts/tests/data/NormalException.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/data/NormalInterface.java b/tests/signature/tests/src/android/signature/cts/tests/data/NormalInterface.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/data/NormalInterface.java
rename to tests/signature/tests/src/android/signature/cts/tests/data/NormalInterface.java
diff --git a/tests/simplecpu/Android.mk b/tests/simplecpu/Android.mk
new file mode 100644
index 0000000..707a380
--- /dev/null
+++ b/tests/simplecpu/Android.mk
@@ -0,0 +1,39 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+
+# Include both the 32 and 64 bit versions
+LOCAL_MULTILIB := both
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+
+LOCAL_JNI_SHARED_LIBRARIES := libctscpu_jni
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsSimpleCpuTestCases
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := 16
+
+include $(BUILD_CTS_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/simplecpu/AndroidManifest.xml b/tests/simplecpu/AndroidManifest.xml
new file mode 100644
index 0000000..4b5febf
--- /dev/null
+++ b/tests/simplecpu/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.simplecpu.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="android.simplecpu.cts"
+            android:label="CTS tests for simple CPU" />
+</manifest>
diff --git a/tests/simplecpu/AndroidTest.xml b/tests/simplecpu/AndroidTest.xml
new file mode 100644
index 0000000..2a347f2
--- /dev/null
+++ b/tests/simplecpu/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS File System test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSimpleCpuTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.simplecpu.cts" />
+        <option name="runtime-hint" value="6m51s" />
+    </test>
+</configuration>
diff --git a/suite/cts/deviceTests/simplecpu/jni/Android.mk b/tests/simplecpu/jni/Android.mk
similarity index 100%
rename from suite/cts/deviceTests/simplecpu/jni/Android.mk
rename to tests/simplecpu/jni/Android.mk
diff --git a/tests/simplecpu/jni/CpuNativeJni.cpp b/tests/simplecpu/jni/CpuNativeJni.cpp
new file mode 100644
index 0000000..4ea0dc0
--- /dev/null
+++ b/tests/simplecpu/jni/CpuNativeJni.cpp
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+
+#include <jni.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+/* Code from now to qsort_local all copied from bionic source.
+ * The code is duplicated here to remove dependency on optimized bionic
+ */
+static __inline char    *med3(char *, char *, char *, int (*)(const void *, const void *));
+static __inline void     swapfunc(char *, char *, int, int);
+
+#define min(a, b)   (a) < (b) ? a : b
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) {       \
+    long i = (n) / sizeof (TYPE);           \
+    TYPE *pi = (TYPE *) (parmi);            \
+    TYPE *pj = (TYPE *) (parmj);            \
+    do {                        \
+        TYPE    t = *pi;            \
+        *pi++ = *pj;                \
+        *pj++ = t;              \
+        } while (--i > 0);              \
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+    es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static __inline void
+swapfunc(char *a, char *b, int n, int swaptype)
+{
+    if (swaptype <= 1)
+        swapcode(long, a, b, n)
+    else
+        swapcode(char, a, b, n)
+}
+
+#define swap(a, b)                  \
+    if (swaptype == 0) {                \
+        long t = *(long *)(a);          \
+        *(long *)(a) = *(long *)(b);        \
+        *(long *)(b) = t;           \
+    } else                      \
+        swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n)    if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+static __inline char *
+med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
+{
+    return cmp(a, b) < 0 ?
+           (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
+              :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
+}
+
+void
+qsort_local(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *))
+{
+    char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+    int d, r, swaptype, swap_cnt;
+    char *a = (char*)aa;
+
+loop:   SWAPINIT(a, es);
+    swap_cnt = 0;
+    if (n < 7) {
+        for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
+            for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+                 pl -= es)
+                swap(pl, pl - es);
+        return;
+    }
+    pm = (char *)a + (n / 2) * es;
+    if (n > 7) {
+        pl = (char *)a;
+        pn = (char *)a + (n - 1) * es;
+        if (n > 40) {
+            d = (n / 8) * es;
+            pl = med3(pl, pl + d, pl + 2 * d, cmp);
+            pm = med3(pm - d, pm, pm + d, cmp);
+            pn = med3(pn - 2 * d, pn - d, pn, cmp);
+        }
+        pm = med3(pl, pm, pn, cmp);
+    }
+    swap(a, pm);
+    pa = pb = (char *)a + es;
+
+    pc = pd = (char *)a + (n - 1) * es;
+    for (;;) {
+        while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+            if (r == 0) {
+                swap_cnt = 1;
+                swap(pa, pb);
+                pa += es;
+            }
+            pb += es;
+        }
+        while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+            if (r == 0) {
+                swap_cnt = 1;
+                swap(pc, pd);
+                pd -= es;
+            }
+            pc -= es;
+        }
+        if (pb > pc)
+            break;
+        swap(pb, pc);
+        swap_cnt = 1;
+        pb += es;
+        pc -= es;
+    }
+    if (swap_cnt == 0) {  /* Switch to insertion sort */
+        for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+            for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+                 pl -= es)
+                swap(pl, pl - es);
+        return;
+    }
+
+    pn = (char *)a + n * es;
+    r = min(pa - (char *)a, pb - pa);
+    vecswap(a, pb - r, r);
+    r = min(pd - pc, pn - pd - (int)es);
+    vecswap(pb, pn - r, r);
+    if ((r = pb - pa) > (int)es)
+        qsort_local(a, r / es, es, cmp);
+    if ((r = pd - pc) > (int)es) {
+        /* Iterate rather than recurse to save stack space */
+        a = pn - r;
+        n = r / es;
+        goto loop;
+    }
+    /* qsort(pn - r, r / es, es, cmp); */
+}
+
+/* code duplication ends here */
+
+/**
+ * Util for getting time stamp
+ */
+double currentTimeMillis()
+{
+    struct timeval tv;
+    gettimeofday(&tv, (struct timezone *) NULL);
+    return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
+}
+
+/**
+ * Initialize given array randomly for the given seed
+ */
+template <typename T> void randomInitArray(T* array, int len, unsigned int seed)
+{
+    srand(seed);
+    for (int i = 0; i < len; i++) {
+        array[i] = (T) rand();
+    }
+}
+
+/**
+ * comparison function for int, for qsort
+ */
+int cmpint(const void* p1, const void* p2)
+{
+    return *(int*)p1 - *(int*)p2;
+}
+
+extern "C" JNIEXPORT jdouble JNICALL Java_android_simplecpu_cts_CpuNative_runSort(JNIEnv* env,
+        jclass clazz, jint numberElements, jint repetition)
+{
+    int* data = new int[numberElements];
+    if (data == NULL) {
+        env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), "No memory");
+        return -1;
+    }
+    double totalTime = 0;
+    for (int i = 0; i < repetition; i++) {
+        randomInitArray<int>(data, numberElements, 0);
+        double start = currentTimeMillis();
+        qsort_local(data, numberElements, sizeof(int), cmpint);
+        double end = currentTimeMillis();
+        totalTime += (end - start);
+    }
+    delete[] data;
+    return totalTime;
+}
+
+
+/**
+ * Do matrix multiplication, C = A x B with all matrices having dimension of n x n
+ * The implementation is not in the most efficient, but it is good enough for benchmarking purpose.
+ * @param n should be multiple of 8
+ */
+void doMatrixMultiplication(float* A, float* B, float* C, int n)
+{
+    // batch size
+    const int M = 8;
+    for (int i = 0; i < n; i++) {
+        for (int j = 0; j < n; j += M) {
+            float sum[M];
+            for (int k = 0; k < M; k++) {
+                sum[k] = 0;
+            }
+            // re-use the whole cache line for accessing B.
+            // otherwise, the whole line will be read and only one value will be used.
+
+            for (int k = 0; k < n; k++) {
+                float a = A[i * n + k];
+                sum[0] += a * B[k * n + j];
+                sum[1] += a * B[k * n + j + 1];
+                sum[2] += a * B[k * n + j + 2];
+                sum[3] += a * B[k * n + j + 3];
+                sum[4] += a * B[k * n + j + 4];
+                sum[5] += a * B[k * n + j + 5];
+                sum[6] += a * B[k * n + j + 6];
+                sum[7] += a * B[k * n + j + 7];
+            }
+            for (int k = 0; k < M; k++) {
+                C[i * n + j + k] = sum[k];
+            }
+        }
+    }
+}
+
+extern "C" JNIEXPORT jdouble JNICALL Java_android_simplecpu_cts_CpuNative_runMatrixMultiplication(
+        JNIEnv* env, jclass clazz, jint n, jint repetition)
+{
+    // C = A x B
+    float* A = new float[n * n];
+    float* B = new float[n * n];
+    float* C = new float[n * n];
+    if ((A == NULL) || (B == NULL) || (C == NULL)) {
+        delete[] A;
+        delete[] B;
+        delete[] C;
+        env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), "No memory");
+        return -1;
+    }
+    double totalTime = 0;
+    for (int i = 0; i < repetition; i++) {
+        randomInitArray<float>(A, n * n, 0);
+        randomInitArray<float>(B, n * n, 1);
+        double start = currentTimeMillis();
+        doMatrixMultiplication(A, B, C, n);
+        double end = currentTimeMillis();
+        totalTime += (end - start);
+    }
+    delete[] A;
+    delete[] B;
+    delete[] C;
+    return totalTime;
+}
+
diff --git a/tests/simplecpu/src/android/simplecpu/cts/CpuNative.java b/tests/simplecpu/src/android/simplecpu/cts/CpuNative.java
new file mode 100644
index 0000000..231cba6
--- /dev/null
+++ b/tests/simplecpu/src/android/simplecpu/cts/CpuNative.java
@@ -0,0 +1,40 @@
+/*
+ * 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 android.simplecpu.cts;
+
+public class CpuNative {
+    static {
+        System.loadLibrary("ctscpu_jni");
+    }
+    /**
+     * run qsort for given number of repetition
+     * with each having the size of bufferSize.
+     * @param numberElements
+     * @param repeatition
+     * @return time taken for computation, added for all repetition in ms
+     */
+    public static native double runSort(int numberElements, int repetition);
+
+    /**
+     * run matrix multiplication of (n x n) x (n x n)
+     *
+     * @param n dimension, should be multiple of 8
+     * @param repetition
+     * @return time taken for computation, added for all repetition in ms
+     */
+    public static native double runMatrixMultiplication(int n, int repetition);
+}
diff --git a/tests/simplecpu/src/android/simplecpu/cts/SimpleCpuTest.java b/tests/simplecpu/src/android/simplecpu/cts/SimpleCpuTest.java
new file mode 100644
index 0000000..fa7f402
--- /dev/null
+++ b/tests/simplecpu/src/android/simplecpu/cts/SimpleCpuTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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 android.simplecpu.cts;
+
+import android.cts.util.CtsAndroidTestCase;
+import android.util.Log;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+import com.android.cts.util.TimeoutReq;
+
+/**
+ * Very simple CPU benchmarking to check the basic capability of CPU.
+ * Cases include
+ *   qsort
+ *   matrix multiplication (for floating point performance)
+ */
+public class SimpleCpuTest extends CtsAndroidTestCase {
+    private static final String TAG = "BandwidthTest";
+    private static final int KB = 1024;
+    private static final int MB = 1024 * 1024;
+    private static final int NUMBER_REPEAT = 20;
+    // reject data outside +/- this value * median
+    private static final double OUTLIER_THRESHOLD = 0.1;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        warmUpCpu();
+    }
+
+    public void testSort004KB() {
+        doTestSort(NUMBER_REPEAT, 4 * KB);
+    }
+
+    public void testSort128KB() {
+        doTestSort(NUMBER_REPEAT, 128 * KB);
+    }
+
+    public void testSort001MB() {
+        doTestSort(NUMBER_REPEAT, 1 * MB);
+    }
+
+    // will fit into L1
+    public void testMatrixMultiplication032() {
+        doMatrixMultiplication(NUMBER_REPEAT, 32);
+    }
+
+    // mostly fit into L2
+    public void testMatrixMultiplication128() {
+        doMatrixMultiplication(NUMBER_REPEAT, 128);
+    }
+
+    // may fit into L2
+    public void testMatrixMultiplication200() {
+        doMatrixMultiplication(NUMBER_REPEAT, 200);
+    }
+
+    public void testMatrixMultiplication400() {
+        doMatrixMultiplication(NUMBER_REPEAT, 400);
+    }
+
+    // will exceed L2
+    @TimeoutReq(minutes = 30)
+    public void testMatrixMultiplication600() {
+        doMatrixMultiplication(NUMBER_REPEAT, 600);
+    }
+
+    /**
+     * run some code to force full CPU freq.
+     */
+    private void warmUpCpu() {
+        CpuNative.runSort(1 * MB, 10);
+    }
+
+    /**
+     * qsort test
+     * @param numberRepeat
+     * @param arrayLength
+     */
+    private void doTestSort(int numberRepeat, int arrayLength) {
+        final int numberRepeatInEachCall = 10;
+        double[] result = new double[numberRepeat];
+        for (int i = 0; i < numberRepeat; i++) {
+            result[i] = CpuNative.runSort(arrayLength, numberRepeatInEachCall);
+        }
+        DeviceReportLog report = new DeviceReportLog();
+        report.addValues("sorting time", result, ResultType.LOWER_BETTER, ResultUnit.MS);
+        Stat.StatResult stat = Stat.getStatWithOutlierRejection(result, OUTLIER_THRESHOLD);
+        if (stat.mDataCount != result.length) {
+            Log.w(TAG, "rejecting " + (result.length - stat.mDataCount) + " outliers");
+        }
+        report.setSummary("sorting time", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.submit(getInstrumentation());
+    }
+
+    /**
+     * Matrix multiplication test, nxn matrix multiplication
+     * @param numberRepeat
+     * @param n should be multiple of 8
+     */
+    private void doMatrixMultiplication(int numberRepeat, int n) {
+        assertTrue(n % 8 == 0);
+        final int numberRepeatInEachCall = 10;
+        double[] result = new double[numberRepeat];
+        for (int i = 0; i < numberRepeat; i++) {
+            result[i] = CpuNative.runMatrixMultiplication(n, numberRepeatInEachCall);
+        }
+        DeviceReportLog report = new DeviceReportLog();
+        report.addValues("matrix mutiplication time", result, ResultType.LOWER_BETTER,
+                ResultUnit.MS);
+        Stat.StatResult stat = Stat.getStatWithOutlierRejection(result, OUTLIER_THRESHOLD);
+        if (stat.mDataCount != result.length) {
+            Log.w(TAG, "rejecting " + (result.length - stat.mDataCount) + " outliers");
+        }
+        report.setSummary("matrix mutiplication time", stat.mAverage,
+                ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.submit(getInstrumentation());
+    }
+
+}
diff --git a/tests/tests/acceleration/Android.mk b/tests/tests/acceleration/Android.mk
deleted file mode 100644
index d417371..0000000
--- a/tests/tests/acceleration/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsAccelerationTestCases
-
-LOCAL_INSTRUMENTATION_FOR := CtsAccelerationTestStubs
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/acceleration/AndroidManifest.xml b/tests/tests/acceleration/AndroidManifest.xml
deleted file mode 100644
index 0dd2722..0000000
--- a/tests/tests/acceleration/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.acceleration">
-
-  <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-  <application>
-      <uses-library android:name="android.test.runner" />
-  </application>
-
-  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                   android:targetPackage="com.android.cts.acceleration.stub"
-                   android:label="Tests for the Hardware Acceleration APIs." >
-        <meta-data android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
-    </instrumentation>
-
-</manifest>
diff --git a/tests/tests/acceleration/src/android/acceleration/cts/BaseAccelerationTest.java b/tests/tests/acceleration/src/android/acceleration/cts/BaseAccelerationTest.java
deleted file mode 100644
index d2f1d9f..0000000
--- a/tests/tests/acceleration/src/android/acceleration/cts/BaseAccelerationTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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 android.acceleration.cts;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.FeatureInfo;
-import android.test.ActivityInstrumentationTestCase2;
-import android.view.View;
-
-abstract class BaseAccelerationTest<B extends BaseAcceleratedActivity>
-        extends ActivityInstrumentationTestCase2<B> {
-
-    protected B mActivity;
-
-    /** View with android:layerType="hardware" set */
-    protected AcceleratedView mHardwareView;
-
-    /** View with android:layerType="software" set */
-    protected AcceleratedView mSoftwareView;
-
-    /** View with setLayerType(HARDWARE) called */
-    protected AcceleratedView mManualHardwareView;
-
-    /** View with setLayerType(SOFTWARE) called */
-    protected AcceleratedView mManualSoftwareView;
-
-    BaseAccelerationTest(Class<B> clazz) {
-        super(clazz);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mHardwareView = mActivity.getHardwareAcceleratedView();
-        mSoftwareView = mActivity.getSoftwareAcceleratedView();
-        mManualHardwareView = mActivity.getManualHardwareAcceleratedView();
-        mManualSoftwareView = mActivity.getManualSoftwareAcceleratedView();
-    }
-
-    public void testNotAttachedView() {
-        // Views that are not attached can't be attached to an accelerated window.
-        View view = new View(mActivity);
-        assertFalse(view.isHardwareAccelerated());
-    }
-
-    protected static int getGlEsVersion(Context context) {
-        ActivityManager activityManager =
-                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-        ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo();
-        if (configInfo.reqGlEsVersion != ConfigurationInfo.GL_ES_VERSION_UNDEFINED) {
-            return getMajorVersion(configInfo.reqGlEsVersion);
-        } else {
-            return 1; // Lack of property means OpenGL ES version 1
-        }
-    }
-
-    /** @see FeatureInfo#getGlEsVersion() */
-    private static int getMajorVersion(int glEsVersion) {
-        return ((glEsVersion & 0xffff0000) >> 16);
-    }
-}
diff --git a/tests/tests/acceleration/src/android/acceleration/cts/HardwareAccelerationTest.java b/tests/tests/acceleration/src/android/acceleration/cts/HardwareAccelerationTest.java
deleted file mode 100644
index eddd34f..0000000
--- a/tests/tests/acceleration/src/android/acceleration/cts/HardwareAccelerationTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 android.acceleration.cts;
-
-/**
- * Test that uses an Activity with hardware acceleration enabled.
- */
-public class HardwareAccelerationTest
-        extends BaseAccelerationTest<HardwareAcceleratedActivity> {
-
-    public HardwareAccelerationTest() {
-        super(HardwareAcceleratedActivity.class);
-    }
-
-    public void testIsHardwareAccelerated() {
-        // Hardware acceleration should be available on devices with GL ES 2 or higher...
-        if (getGlEsVersion(mActivity) >= 2) {
-            // Both of the views are attached to a hardware accelerated window
-            assertTrue(mHardwareView.isHardwareAccelerated());
-            assertTrue(mSoftwareView.isHardwareAccelerated());
-            assertTrue(mManualHardwareView.isHardwareAccelerated());
-            assertTrue(mManualSoftwareView.isHardwareAccelerated());
-
-            assertTrue(mHardwareView.isCanvasHardwareAccelerated());
-            assertFalse(mSoftwareView.isCanvasHardwareAccelerated());
-            assertTrue(mManualHardwareView.isCanvasHardwareAccelerated());
-            assertFalse(mManualSoftwareView.isCanvasHardwareAccelerated());
-        } else {
-            assertFalse(mHardwareView.isHardwareAccelerated());
-            assertFalse(mSoftwareView.isHardwareAccelerated());
-            assertFalse(mManualHardwareView.isHardwareAccelerated());
-            assertFalse(mManualSoftwareView.isHardwareAccelerated());
-
-            assertFalse(mHardwareView.isCanvasHardwareAccelerated());
-            assertFalse(mSoftwareView.isCanvasHardwareAccelerated());
-            assertFalse(mManualHardwareView.isCanvasHardwareAccelerated());
-            assertFalse(mManualSoftwareView.isCanvasHardwareAccelerated());
-        }
-    }
-}
diff --git a/tests/tests/acceleration/src/android/acceleration/cts/SoftwareAccelerationTest.java b/tests/tests/acceleration/src/android/acceleration/cts/SoftwareAccelerationTest.java
deleted file mode 100644
index 146fa6a..0000000
--- a/tests/tests/acceleration/src/android/acceleration/cts/SoftwareAccelerationTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 android.acceleration.cts;
-
-/**
- * Test that uses an Activity with hardware acceleration explicitly disabled
- * and makes sure that all views are rendered using software acceleration.
- */
-public class SoftwareAccelerationTest
-        extends BaseAccelerationTest<SoftwareAcceleratedActivity> {
-
-    public SoftwareAccelerationTest() {
-        super(SoftwareAcceleratedActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
-    public void testIsHardwareAccelerated() {
-        // Both of the views are not attached to a hardware accelerated window
-        assertFalse(mHardwareView.isHardwareAccelerated());
-        assertFalse(mSoftwareView.isHardwareAccelerated());
-        assertFalse(mManualHardwareView.isHardwareAccelerated());
-        assertFalse(mManualSoftwareView.isHardwareAccelerated());
-
-        assertFalse(mHardwareView.isCanvasHardwareAccelerated());
-        assertFalse(mSoftwareView.isCanvasHardwareAccelerated());
-        assertFalse(mManualHardwareView.isCanvasHardwareAccelerated());
-        assertFalse(mManualSoftwareView.isCanvasHardwareAccelerated());
-    }
-}
diff --git a/tests/tests/acceleration/src/android/acceleration/cts/WindowFlagHardwareAccelerationTest.java b/tests/tests/acceleration/src/android/acceleration/cts/WindowFlagHardwareAccelerationTest.java
deleted file mode 100644
index bfbbe63..0000000
--- a/tests/tests/acceleration/src/android/acceleration/cts/WindowFlagHardwareAccelerationTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 android.acceleration.cts;
-
-/**
- * Test that uses an Activity with hardware acceleration enabled.
- */
-public class WindowFlagHardwareAccelerationTest
-        extends BaseAccelerationTest<WindowFlagHardwareAcceleratedActivity> {
-
-    public WindowFlagHardwareAccelerationTest() {
-        super(WindowFlagHardwareAcceleratedActivity.class);
-    }
-
-    public void testIsHardwareAccelerated() {
-        // Hardware acceleration should be available on devices with GL ES 2 or higher...
-        if (getGlEsVersion(mActivity) >= 2) {
-            // Both of the views are attached to a hardware accelerated window
-            assertTrue(mHardwareView.isHardwareAccelerated());
-            assertTrue(mSoftwareView.isHardwareAccelerated());
-            assertTrue(mManualHardwareView.isHardwareAccelerated());
-            assertTrue(mManualSoftwareView.isHardwareAccelerated());
-
-            assertTrue(mHardwareView.isCanvasHardwareAccelerated());
-            assertFalse(mSoftwareView.isCanvasHardwareAccelerated());
-            assertTrue(mManualHardwareView.isCanvasHardwareAccelerated());
-            assertFalse(mManualSoftwareView.isCanvasHardwareAccelerated());
-        } else {
-            assertFalse(mHardwareView.isHardwareAccelerated());
-            assertFalse(mSoftwareView.isHardwareAccelerated());
-            assertFalse(mManualHardwareView.isHardwareAccelerated());
-            assertFalse(mManualSoftwareView.isHardwareAccelerated());
-
-            assertFalse(mHardwareView.isCanvasHardwareAccelerated());
-            assertFalse(mSoftwareView.isCanvasHardwareAccelerated());
-            assertFalse(mManualHardwareView.isCanvasHardwareAccelerated());
-            assertFalse(mManualSoftwareView.isCanvasHardwareAccelerated());
-        }
-    }
-}
diff --git a/tests/tests/accessibility/Android.mk b/tests/tests/accessibility/Android.mk
deleted file mode 100644
index 263c47b..0000000
--- a/tests/tests/accessibility/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsAccessibilityTestCases
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/accessibility/AndroidManifest.xml b/tests/tests/accessibility/AndroidManifest.xml
deleted file mode 100644
index b3bcbc8..0000000
--- a/tests/tests/accessibility/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- * 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.view.cts.accessibility">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
-    <application android:theme="@android:style/Theme.Holo.NoActionBar" >
-        <uses-library android:name="android.test.runner"/>
-    </application>
-
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.view.cts.accessibility"
-                     android:label="Tests for the accessibility APIs.">
-        <meta-data android:name="listener"
-                   android:value="com.android.cts.runner.CtsTestRunListener" />
-    </instrumentation>
-
-</manifest>
diff --git a/tests/tests/accessibility/AndroidTest.xml b/tests/tests/accessibility/AndroidTest.xml
deleted file mode 100644
index 7832508..0000000
--- a/tests/tests/accessibility/AndroidTest.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Base config for CTS package preparer">
-    <include name="common-config" />
-    <option name="run-command:run-command" value="settings put secure enabled_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
-    <option name="run-command:run-command" value="settings put secure touch_exploration_granted_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
-    <option name="run-command:run-command" value="settings put secure accessibility_enabled 1" />
-    <option name="run-command:teardown-command" value="settings put secure enabled_accessibility_services &quot;&quot;" />
-    <option name="run-command:teardown-command" value="settings put secure touch_exploration_granted_accessibility_services &quot;&quot;" />
-    <option name="run-command:teardown-command" value="settings put secure accessibility_enabled 0" />
-    <option name="cts-apk-installer:test-file-name" value="CtsSomeAccessibilityServices.apk" />
-</configuration>
diff --git a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
deleted file mode 100644
index 506c022..0000000
--- a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * 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 android.view.accessibility.cts;
-
-import android.graphics.Rect;
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import android.view.cts.accessibility.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Class for testing {@link AccessibilityNodeInfo}.
- */
-public class AccessibilityNodeInfoTest extends AndroidTestCase {
-
-    /** The number of properties of the {@link AccessibilityNodeInfo} class. */
-    private static final int NON_STATIC_FIELD_COUNT = 30;
-
-    @SmallTest
-    public void testMarshaling() throws Exception {
-        // no new fields, so we are testing marshaling of all such
-        AccessibilityRecordTest.assertNoNewNonStaticFieldsAdded(AccessibilityNodeInfo.class,
-                NON_STATIC_FIELD_COUNT);
-
-        // fully populate the node info to marshal
-        AccessibilityNodeInfo sentInfo = AccessibilityNodeInfo.obtain(new View(getContext()));
-        fullyPopulateAccessibilityNodeInfo(sentInfo);
-
-        // marshal and unmarshal the node info
-        Parcel parcel = Parcel.obtain();
-        sentInfo.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        AccessibilityNodeInfo receivedInfo = AccessibilityNodeInfo.CREATOR.createFromParcel(parcel);
-
-        // make sure all fields properly marshaled
-        assertEqualsAccessibilityNodeInfo(sentInfo, receivedInfo);
-    }
-
-    /**
-     * Tests if {@link AccessibilityNodeInfo}s are properly reused.
-     */
-    @SmallTest
-    public void testReuse() {
-        AccessibilityEvent firstInfo = AccessibilityEvent.obtain();
-        firstInfo.recycle();
-        AccessibilityEvent secondInfo = AccessibilityEvent.obtain();
-        assertSame("AccessibilityNodeInfo not properly reused", firstInfo, secondInfo);
-    }
-
-    /**
-     * Tests if {@link AccessibilityNodeInfo} are properly recycled.
-     */
-    @SmallTest
-    public void testRecycle() {
-        // obtain and populate an node info
-        AccessibilityNodeInfo populatedInfo = AccessibilityNodeInfo.obtain();
-        fullyPopulateAccessibilityNodeInfo(populatedInfo);
-
-        // recycle and obtain the same recycled instance
-        populatedInfo.recycle();
-        AccessibilityNodeInfo recycledInfo = AccessibilityNodeInfo.obtain();
-
-        // check expectations
-        assertAccessibilityNodeInfoCleared(recycledInfo);
-    }
-
-    /**
-     * Tests whether the event describes its contents consistently.
-     */
-    @SmallTest
-    public void testDescribeContents() {
-        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
-        assertSame("Accessibility node infos always return 0 for this method.", 0,
-                info.describeContents());
-        fullyPopulateAccessibilityNodeInfo(info);
-        assertSame("Accessibility node infos always return 0 for this method.", 0,
-                info.describeContents());
-    }
-
-    /**
-     * Tests whether accessibility actions are properly added.
-     */
-    @SmallTest
-    public void testAddActions() {
-        List<AccessibilityAction> customActions = new ArrayList<AccessibilityAction>();
-        customActions.add(new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS, "Foo"));
-        customActions.add(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
-
-        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
-        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
-        info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
-        for (AccessibilityAction customAction : customActions) {
-            info.addAction(customAction);
-        }
-
-        assertSame(info.getActions(), (AccessibilityNodeInfo.ACTION_FOCUS
-                | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS));
-
-        List<AccessibilityAction> allActions = new ArrayList<AccessibilityAction>();
-        allActions.add(AccessibilityAction.ACTION_CLEAR_FOCUS);
-        allActions.addAll(customActions);
-        assertEquals(info.getActionList(), allActions);
-    }
-
-    /**
-     * Tests whether we catch addition of an action with invalid id.
-     */
-    @SmallTest
-    public void testCreateInvalidActionId() {
-        try {
-            new AccessibilityAction(3, null);
-        } catch (IllegalArgumentException iae) {
-            /* expected */
-        }
-    }
-
-    /**
-     * Tests whether accessibility actions are properly removed.
-     */
-    @SmallTest
-    public void testRemoveActions() {
-        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
-
-        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
-        assertSame(info.getActions(), AccessibilityNodeInfo.ACTION_FOCUS);
-
-        info.removeAction(AccessibilityNodeInfo.ACTION_FOCUS);
-        assertSame(info.getActions(), 0);
-        assertTrue(info.getActionList().isEmpty());
-
-        AccessibilityAction customFocus = new AccessibilityAction(
-                AccessibilityNodeInfo.ACTION_FOCUS, "Foo");
-        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
-        info.addAction(customFocus);
-        assertSame(info.getActionList().size(), 1);
-        assertEquals(info.getActionList().get(0), customFocus);
-        assertSame(info.getActions(), AccessibilityNodeInfo.ACTION_FOCUS);
-
-        info.removeAction(customFocus);
-        assertSame(info.getActions(), 0);
-        assertTrue(info.getActionList().isEmpty());
-    }
-
-    /**
-     * Fully populates the {@link AccessibilityNodeInfo} to marshal.
-     *
-     * @param info The node info to populate.
-     */
-    private void fullyPopulateAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        info.setParent(new View(getContext()));
-        info.setSource(new View(getContext()));
-        info.addChild(new View(getContext()));
-        info.addChild(new View(getContext()), 1);
-        info.setBoundsInParent(new Rect(1,1,1,1));
-        info.setBoundsInScreen(new Rect(2,2,2,2));
-        info.setClassName("foo.bar.baz.Class");
-        info.setContentDescription("content description");
-        info.setPackageName("foo.bar.baz");
-        info.setText("text");
-        info.setCheckable(true);
-        info.setChecked(true);
-        info.setClickable(true);
-        info.setEnabled(true);
-        info.setFocusable(true);
-        info.setFocused(true);
-        info.setLongClickable(true);
-        info.setContextClickable(true);
-        info.setPassword(true);
-        info.setScrollable(true);
-        info.setSelected(true);
-        info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
-        info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
-        info.addAction(new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS, "Foo"));
-        info.addAction(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
-        info.setAccessibilityFocused(true);
-        info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-        info.setLabeledBy(new View(getContext()));
-        info.setLabelFor(new View(getContext()));
-        info.setViewIdResourceName("foo.bar:id/baz");
-    }
-
-    /**
-     * Compares all properties of the <code>expectedInfo</code> and the
-     * <code>receviedInfo</code> to verify that the received node info is
-     * the one that is expected.
-     */
-    public static void assertEqualsAccessibilityNodeInfo(AccessibilityNodeInfo expectedInfo,
-            AccessibilityNodeInfo receivedInfo) {
-        Rect expectedBounds = new Rect();
-        Rect receivedBounds = new Rect();
-        expectedInfo.getBoundsInParent(expectedBounds);
-        receivedInfo.getBoundsInParent(receivedBounds);
-        assertEquals("boundsInParent has incorrect value", expectedBounds, receivedBounds);
-        expectedInfo.getBoundsInScreen(expectedBounds);
-        receivedInfo.getBoundsInScreen(receivedBounds);
-        assertEquals("boundsInScreen has incorrect value", expectedBounds, receivedBounds);
-        assertEquals("className has incorrect value", expectedInfo.getClassName(),
-                receivedInfo.getClassName());
-        assertEquals("contentDescription has incorrect value", expectedInfo.getContentDescription(),
-                receivedInfo.getContentDescription());
-        assertEquals("packageName has incorrect value", expectedInfo.getPackageName(),
-                receivedInfo.getPackageName());
-        assertEquals("text has incorrect value", expectedInfo.getText(), receivedInfo.getText());
-        assertSame("checkable has incorrect value", expectedInfo.isCheckable(),
-                receivedInfo.isCheckable());
-        assertSame("checked has incorrect value", expectedInfo.isChecked(),
-                receivedInfo.isChecked());
-        assertSame("clickable has incorrect value", expectedInfo.isClickable(),
-                receivedInfo.isClickable());
-        assertSame("enabled has incorrect value", expectedInfo.isEnabled(),
-                receivedInfo.isEnabled());
-        assertSame("focusable has incorrect value", expectedInfo.isFocusable(),
-                receivedInfo.isFocusable());
-        assertSame("focused has incorrect value", expectedInfo.isFocused(),
-                receivedInfo.isFocused());
-        assertSame("longClickable has incorrect value", expectedInfo.isLongClickable(),
-                receivedInfo.isLongClickable());
-        assertSame("contextClickable has incorrect value", expectedInfo.isContextClickable(),
-                receivedInfo.isContextClickable());
-        assertSame("password has incorrect value", expectedInfo.isPassword(),
-                receivedInfo.isPassword());
-        assertSame("scrollable has incorrect value", expectedInfo.isScrollable(),
-                receivedInfo.isScrollable());
-        assertSame("selected has incorrect value", expectedInfo.isSelected(),
-                receivedInfo.isSelected());
-        assertSame("actions has incorrect value", expectedInfo.getActions(),
-                receivedInfo.getActions());
-        assertEquals("actionsSet has incorrect value", expectedInfo.getActionList(),
-                receivedInfo.getActionList());
-        assertSame("childCount has incorrect value", expectedInfo.getChildCount(),
-                receivedInfo.getChildCount());
-        assertSame("childCount has incorrect value", expectedInfo.getChildCount(),
-                receivedInfo.getChildCount());
-        assertSame("accessibilityFocused has incorrect value",
-                expectedInfo.isAccessibilityFocused(),
-                receivedInfo.isAccessibilityFocused());
-        assertSame("movementGranularities has incorrect value",
-                expectedInfo.getMovementGranularities(),
-                receivedInfo.getMovementGranularities());
-        assertEquals("viewId has incorrect value", expectedInfo.getViewIdResourceName(),
-                receivedInfo.getViewIdResourceName());
-    }
-
-    /**
-     * Asserts that an {@link AccessibilityNodeInfo} is cleared.
-     *
-     * @param info The node info to check.
-     */
-    public static void assertAccessibilityNodeInfoCleared(AccessibilityNodeInfo info) {
-        Rect bounds = new Rect();
-        info.getBoundsInParent(bounds);
-        assertTrue("boundsInParent not properly recycled", bounds.isEmpty());
-        info.getBoundsInScreen(bounds);
-        assertTrue("boundsInScreen not properly recycled", bounds.isEmpty());
-        assertNull("className not properly recycled", info.getClassName());
-        assertNull("contentDescription not properly recycled", info.getContentDescription());
-        assertNull("packageName not properly recycled", info.getPackageName());
-        assertNull("text not properly recycled", info.getText());
-        assertFalse("checkable not properly recycled", info.isCheckable());
-        assertFalse("checked not properly recycled", info.isChecked());
-        assertFalse("clickable not properly recycled", info.isClickable());
-        assertFalse("enabled not properly recycled", info.isEnabled());
-        assertFalse("focusable not properly recycled", info.isFocusable());
-        assertFalse("focused not properly recycled", info.isFocused());
-        assertFalse("longClickable not properly recycled", info.isLongClickable());
-        assertFalse("contextClickable not properly recycled", info.isContextClickable());
-        assertFalse("password not properly recycled", info.isPassword());
-        assertFalse("scrollable not properly recycled", info.isScrollable());
-        assertFalse("selected not properly recycled", info.isSelected());
-        assertSame("actions not properly recycled", 0, info.getActions());
-        assertFalse("accessibilityFocused not properly recycled", info.isAccessibilityFocused());
-        assertSame("movementGranularities not properly recycled", 0,
-                info.getMovementGranularities());
-        assertNull("viewId not properly recycled", info.getViewIdResourceName());
-    }
-}
diff --git a/tests/tests/accessibilityservice/Android.mk b/tests/tests/accessibilityservice/Android.mk
deleted file mode 100644
index b27dbcc..0000000
--- a/tests/tests/accessibilityservice/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsAccessibilityServiceTestCases
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/accessibilityservice/AndroidManifest.xml b/tests/tests/accessibilityservice/AndroidManifest.xml
deleted file mode 100644
index e172913..0000000
--- a/tests/tests/accessibilityservice/AndroidManifest.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.accessibilityservice">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
-    <application android:theme="@android:style/Theme.Holo.NoActionBar" >
-
-      <uses-library android:name="android.test.runner"/>
-
-      <activity android:label="@string/accessibility_end_to_end_test_activity"
-              android:name="android.accessibilityservice.cts.AccessibilityEndToEndActivity"/>
-
-      <activity android:label="@string/accessibility_query_window_test_activity"
-              android:name="android.accessibilityservice.cts.AccessibilityWindowQueryActivity"/>
-
-      <activity android:label="@string/accessibility_view_tree_reporting_test_activity"
-              android:name="android.accessibilityservice.cts.AccessibilityViewTreeReportingActivity"/>
-
-      <activity android:label="@string/accessibility_focus_and_input_focus_sync_test_activity"
-              android:name="android.accessibilityservice.cts.AccessibilityFocusAndInputFocusSyncActivity"/>
-
-      <activity android:label="@string/accessibility_text_traversal_test_activity"
-              android:name="android.accessibilityservice.cts.AccessibilityTextTraversalActivity"/>
-
-  </application>
-
-  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                   android:targetPackage="com.android.cts.accessibilityservice"
-                   android:label="Tests for the accessibility APIs.">
-        <meta-data android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
-    </instrumentation>
-
-</manifest>
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndActivity.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndActivity.java
deleted file mode 100644
index 157a3dc..0000000
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndActivity.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.
- */
-
-package android.accessibilityservice.cts;
-
-import com.android.cts.accessibilityservice.R;
-
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-
-/**
- * This class is an {@link android.app.Activity} used to perform end-to-end
- * testing of the accessibility feature by interaction with the
- * UI widgets.
- */
-public class AccessibilityEndToEndActivity extends AccessibilityTestActivity {
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.end_to_end_test);
-
-        ListAdapter listAdapter = new BaseAdapter() {
-            public View getView(int position, View convertView, ViewGroup parent) {
-                TextView textView = (TextView) View
-                        .inflate(AccessibilityEndToEndActivity.this, R.layout.list_view_row, null);
-                textView.setText((String) getItem(position));
-                return textView;
-            }
-
-            public long getItemId(int position) {
-                return position;
-            }
-
-            public Object getItem(int position) {
-                if (position == 0) {
-                    return AccessibilityEndToEndActivity.this.getString(R.string.first_list_item);
-                } else {
-                    return AccessibilityEndToEndActivity.this.getString(R.string.second_list_item);
-                }
-            }
-
-            public int getCount() {
-                return 2;
-            }
-        };
-
-        ListView listView = (ListView) findViewById(R.id.listview);
-        listView.setAdapter(listAdapter);
-    }
-}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
deleted file mode 100644
index f5b29cf..0000000
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * 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.
- */
-
-package android.accessibilityservice.cts;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.app.UiAutomation;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ListView;
-
-import com.android.cts.accessibilityservice.R;
-
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * This class performs end-to-end testing of the accessibility feature by
- * creating an {@link Activity} and poking around so {@link AccessibilityEvent}s
- * are generated and their correct dispatch verified.
- */
-public class AccessibilityEndToEndTest extends
-        AccessibilityActivityTestCase<AccessibilityEndToEndActivity> {
-
-    private static final String LOG_TAG = "AccessibilityEndToEndTest";
-
-    /**
-     * Creates a new instance for testing {@link AccessibilityEndToEndActivity}.
-     */
-    public AccessibilityEndToEndTest() {
-        super(AccessibilityEndToEndActivity.class);
-    }
-
-    @MediumTest
-    public void testTypeViewSelectedAccessibilityEvent() throws Throwable {
-        // create and populate the expected event
-        final AccessibilityEvent expected = AccessibilityEvent.obtain();
-        expected.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED);
-        expected.setClassName(ListView.class.getName());
-        expected.setPackageName(getActivity().getPackageName());
-        expected.getText().add(getActivity().getString(R.string.second_list_item));
-        expected.setItemCount(2);
-        expected.setCurrentItemIndex(1);
-        expected.setEnabled(true);
-        expected.setScrollable(false);
-        expected.setFromIndex(0);
-        expected.setToIndex(1);
-
-        final ListView listView = (ListView) getActivity().findViewById(R.id.listview);
-
-        AccessibilityEvent awaitedEvent =
-            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
-                new Runnable() {
-            @Override
-            public void run() {
-                // trigger the event
-                getActivity().runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        listView.setSelection(1);
-                    }
-                });
-            }},
-            new UiAutomation.AccessibilityEventFilter() {
-                // check the received event
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return equalsAccessiblityEvent(event, expected);
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
-    }
-
-    @MediumTest
-    public void testTypeViewClickedAccessibilityEvent() throws Throwable {
-        // create and populate the expected event
-        final AccessibilityEvent expected = AccessibilityEvent.obtain();
-        expected.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
-        expected.setClassName(Button.class.getName());
-        expected.setPackageName(getActivity().getPackageName());
-        expected.getText().add(getActivity().getString(R.string.button_title));
-        expected.setEnabled(true);
-
-        final Button button = (Button) getActivity().findViewById(R.id.button);
-
-        AccessibilityEvent awaitedEvent =
-            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
-                new Runnable() {
-            @Override
-            public void run() {
-                // trigger the event
-                getActivity().runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        button.performClick();
-                    }
-                });
-            }},
-            new UiAutomation.AccessibilityEventFilter() {
-                // check the received event
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return equalsAccessiblityEvent(event, expected);
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
-    }
-
-    @MediumTest
-    public void testTypeViewLongClickedAccessibilityEvent() throws Throwable {
-        // create and populate the expected event
-        final AccessibilityEvent expected = AccessibilityEvent.obtain();
-        expected.setEventType(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
-        expected.setClassName(Button.class.getName());
-        expected.setPackageName(getActivity().getPackageName());
-        expected.getText().add(getActivity().getString(R.string.button_title));
-        expected.setEnabled(true);
-
-        final Button button = (Button) getActivity().findViewById(R.id.button);
-
-        AccessibilityEvent awaitedEvent =
-            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
-                new Runnable() {
-            @Override
-            public void run() {
-                // trigger the event
-                getActivity().runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        button.performLongClick();
-                    }
-                });
-            }},
-            new UiAutomation.AccessibilityEventFilter() {
-                // check the received event
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return equalsAccessiblityEvent(event, expected);
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
-    }
-
-    @MediumTest
-    public void testTypeViewFocusedAccessibilityEvent() throws Throwable {
-        // create and populate the expected event
-        final AccessibilityEvent expected = AccessibilityEvent.obtain();
-        expected.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
-        expected.setClassName(Button.class.getName());
-        expected.setPackageName(getActivity().getPackageName());
-        expected.getText().add(getActivity().getString(R.string.button_title));
-        expected.setItemCount(3);
-        expected.setCurrentItemIndex(2);
-        expected.setEnabled(true);
-
-        final Button button = (Button) getActivity().findViewById(R.id.button);
-
-        AccessibilityEvent awaitedEvent =
-            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
-                new Runnable() {
-            @Override
-            public void run() {
-                // trigger the event
-                getActivity().runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        button.requestFocus();
-                    }
-                });
-            }},
-            new UiAutomation.AccessibilityEventFilter() {
-                // check the received event
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return equalsAccessiblityEvent(event, expected);
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
-    }
-
-    @MediumTest
-    public void testTypeViewTextChangedAccessibilityEvent() throws Throwable {
-        // focus the edit text
-        final EditText editText = (EditText) getActivity().findViewById(R.id.edittext);
-
-        AccessibilityEvent awaitedFocusEvent =
-            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
-                new Runnable() {
-            @Override
-            public void run() {
-                // trigger the event
-                getActivity().runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        editText.requestFocus();
-                    }
-                });
-            }},
-            new UiAutomation.AccessibilityEventFilter() {
-                // check the received event
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED;
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-        assertNotNull("Did not receive expected focuss event.", awaitedFocusEvent);
-
-        final String beforeText = getActivity().getString(R.string.text_input_blah);
-        final String newText = getActivity().getString(R.string.text_input_blah_blah);
-        final String afterText = beforeText.substring(0, 3) + newText;
-
-        // create and populate the expected event
-        final AccessibilityEvent expected = AccessibilityEvent.obtain();
-        expected.setEventType(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
-        expected.setClassName(EditText.class.getName());
-        expected.setPackageName(getActivity().getPackageName());
-        expected.getText().add(afterText);
-        expected.setBeforeText(beforeText);
-        expected.setFromIndex(3);
-        expected.setAddedCount(9);
-        expected.setRemovedCount(1);
-        expected.setEnabled(true);
-
-        AccessibilityEvent awaitedTextChangeEvent =
-            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
-                new Runnable() {
-            @Override
-            public void run() {
-                // trigger the event
-                getActivity().runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        editText.getEditableText().replace(3, 4, newText);
-                    }
-                });
-            }},
-            new UiAutomation.AccessibilityEventFilter() {
-                // check the received event
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return equalsAccessiblityEvent(event, expected);
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-        assertNotNull("Did not receive expected event: " + expected, awaitedTextChangeEvent);
-    }
-
-    @MediumTest
-    public void testTypeWindowStateChangedAccessibilityEvent() throws Throwable {
-        // create and populate the expected event
-        final AccessibilityEvent expected = AccessibilityEvent.obtain();
-        expected.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-        expected.setClassName(AlertDialog.class.getName());
-        expected.setPackageName(getActivity().getPackageName());
-        expected.getText().add(getActivity().getString(R.string.alert_title));
-        expected.getText().add(getActivity().getString(R.string.alert_message));
-        expected.setEnabled(true);
-
-        AccessibilityEvent awaitedEvent =
-            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
-                new Runnable() {
-            @Override
-            public void run() {
-                // trigger the event
-                getActivity().runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        (new AlertDialog.Builder(getActivity()).setTitle(R.string.alert_title)
-                                .setMessage(R.string.alert_message)).create().show();
-                    }
-                });
-            }},
-            new UiAutomation.AccessibilityEventFilter() {
-                // check the received event
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return equalsAccessiblityEvent(event, expected);
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
-    }
-
-    @MediumTest
-    @SuppressWarnings("deprecation")
-    public void testTypeNotificationStateChangedAccessibilityEvent() throws Throwable {
-        // No notification UI on televisions.
-        if((getActivity().getResources().getConfiguration().uiMode
-                & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) {
-            Log.i(LOG_TAG, "Skipping: testTypeNotificationStateChangedAccessibilityEvent" +
-                    " - No notification UI on televisions.");
-            return;
-        }
-
-        String message = getActivity().getString(R.string.notification_message);
-
-        // create the notification to send
-        final int notificationId = 1;
-        final Notification notification = new Notification.Builder(getActivity())
-                .setSmallIcon(android.R.drawable.stat_notify_call_mute)
-                .setContentIntent(PendingIntent.getActivity(getActivity(), 0, new Intent(),
-                        PendingIntent.FLAG_CANCEL_CURRENT))
-                .setTicker(message)
-                .setContentTitle("")
-                .setContentText("")
-                // Mark the notification as "interruptive" by specifying a vibration pattern. This
-                // ensures it's announced properly on watch-type devices.
-                .setVibrate(new long[] {})
-                .build();
-
-        // create and populate the expected event
-        final AccessibilityEvent expected = AccessibilityEvent.obtain();
-        expected.setEventType(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
-        expected.setClassName(Notification.class.getName());
-        expected.setPackageName(getActivity().getPackageName());
-        expected.getText().add(message);
-        expected.setParcelableData(notification);
-
-        AccessibilityEvent awaitedEvent =
-            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
-                new Runnable() {
-            @Override
-            public void run() {
-                // trigger the event
-                getActivity().runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        // trigger the event
-                        NotificationManager notificationManager =
-                            (NotificationManager) getActivity().getSystemService(
-                                    Service.NOTIFICATION_SERVICE);
-                        notificationManager.notify(notificationId, notification);
-                        getActivity().finish();
-                    }
-                });
-            }},
-            new UiAutomation.AccessibilityEventFilter() {
-                // check the received event
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return equalsAccessiblityEvent(event, expected);
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
-    }
-
-    /**
-     * Compares all properties of the <code>first</code> and the
-     * <code>second</code>.
-     */
-    private boolean equalsAccessiblityEvent(AccessibilityEvent first, AccessibilityEvent second) {
-         return first.getEventType() == second.getEventType()
-            && first.isChecked() == second.isChecked()
-            && first.getCurrentItemIndex() == second.getCurrentItemIndex()
-            && first.isEnabled() == second.isEnabled()
-            && first.getFromIndex() == second.getFromIndex()
-            && first.getItemCount() == second.getItemCount()
-            && first.isPassword() == second.isPassword()
-            && first.getRemovedCount() == second.getRemovedCount()
-            && first.isScrollable()== second.isScrollable()
-            && first.getToIndex() == second.getToIndex()
-            && first.getRecordCount() == second.getRecordCount()
-            && first.getScrollX() == second.getScrollX()
-            && first.getScrollY() == second.getScrollY()
-            && first.getAddedCount() == second.getAddedCount()
-            && TextUtils.equals(first.getBeforeText(), second.getBeforeText())
-            && TextUtils.equals(first.getClassName(), second.getClassName())
-            && TextUtils.equals(first.getContentDescription(), second.getContentDescription())
-            && equalsNotificationAsParcelableData(first, second)
-            && equalsText(first, second);
-    }
-
-    /**
-     * Compares the {@link android.os.Parcelable} data of the
-     * <code>first</code> and <code>second</code>.
-     */
-    private boolean equalsNotificationAsParcelableData(AccessibilityEvent first,
-            AccessibilityEvent second) {
-        Notification firstNotification = (Notification) first.getParcelableData();
-        Notification secondNotification = (Notification) second.getParcelableData();
-        if (firstNotification == null) {
-            return (secondNotification == null);
-        } else if (secondNotification == null) {
-            return false;
-        }
-        return TextUtils.equals(firstNotification.tickerText, secondNotification.tickerText);
-    }
-
-    /**
-     * Compares the text of the <code>first</code> and <code>second</code> text.
-     */
-    private boolean equalsText(AccessibilityEvent first, AccessibilityEvent second) {
-        List<CharSequence> firstText = first.getText();
-        List<CharSequence> secondText = second.getText();
-        if (firstText.size() != secondText.size()) {
-            return false;
-        }
-        Iterator<CharSequence> firstIterator = firstText.iterator();
-        Iterator<CharSequence> secondIterator = secondText.iterator();
-        for (int i = 0; i < firstText.size(); i++) {
-            if (!firstIterator.next().toString().equals(secondIterator.next().toString())) {
-                return false;
-            }
-        }
-        return true;
-    }
-}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncActivity.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncActivity.java
deleted file mode 100644
index 46f04aa..0000000
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncActivity.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * 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 android.accessibilityservice.cts;
-
-import android.os.Bundle;
-
-import com.android.cts.accessibilityservice.R;
-
-/**
- * Activity for testing the accessibility focus APIs exposed to
- * accessibility services. These APIs allow moving accessibility
- * focus in the view tree from an AccessiiblityService. Specifically,
- * this activity is for verifying the the sync between accessibility
- * and input focus.
- */
-public class AccessibilityFocusAndInputFocusSyncActivity extends AccessibilityTestActivity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.accessibility_focus_and_input_focus_sync_test);
-    }
-}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
deleted file mode 100644
index 93b026c..0000000
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/**
- * 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 android.accessibilityservice.cts;
-
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
-
-import android.app.UiAutomation;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import com.android.cts.accessibilityservice.R;
-
-import java.util.LinkedList;
-import java.util.Queue;
-
-/**
- * Test cases for testing the accessibility focus APIs exposed to accessibility
- * services. These APIs allow moving accessibility focus in the view tree from
- * an AccessiiblityService. Specifically, this activity is for verifying the the
- * sync between accessibility and input focus.
- */
-public class AccessibilityFocusAndInputFocusSyncTest
-        extends AccessibilityActivityTestCase<AccessibilityFocusAndInputFocusSyncActivity>{
-
-    public AccessibilityFocusAndInputFocusSyncTest() {
-        super(AccessibilityFocusAndInputFocusSyncActivity.class);
-    }
-
-    @MediumTest
-    public void testFindAccessibilityFocus() throws Exception {
-        // Get the view that has input and accessibility focus.
-        final AccessibilityNodeInfo expected = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.firstEditText)).get(0);
-        assertNotNull(expected);
-        assertFalse(expected.isAccessibilityFocused());
-        assertTrue(expected.isFocused());
-
-        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                // Perform a focus action and check for success.
-                assertTrue(expected.performAction(ACTION_ACCESSIBILITY_FOCUS));
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Get the second expected node info.
-        AccessibilityNodeInfo received = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
-        assertNotNull(received);
-        assertTrue(received.isAccessibilityFocused());
-
-        // Make sure we got the expected focusable.
-        assertEquals(expected, received);
-    }
-
-    @MediumTest
-    public void testInitialStateNoAccessibilityFocus() throws Exception {
-        // Get the root which is only accessibility focused.
-        AccessibilityNodeInfo focused = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
-        assertNull(focused);
-    }
-
-    @MediumTest
-    public void testActionAccessibilityFocus() throws Exception {
-        // Get the root linear layout info.
-        final AccessibilityNodeInfo rootLinearLayout = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.rootLinearLayout)).get(0);
-        assertNotNull(rootLinearLayout);
-        assertFalse(rootLinearLayout.isAccessibilityFocused());
-
-        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                // Perform a focus action and check for success.
-                assertTrue(rootLinearLayout.performAction(ACTION_ACCESSIBILITY_FOCUS));
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Get the node info again.
-        rootLinearLayout.refresh();
-
-        // Check if the node info is focused.
-        assertTrue(rootLinearLayout.isAccessibilityFocused());
-    }
-
-    @MediumTest
-    public void testActionClearAccessibilityFocus() throws Exception {
-        // Get the root linear layout info.
-        final AccessibilityNodeInfo rootLinearLayout = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.rootLinearLayout)).get(0);
-        assertNotNull(rootLinearLayout);
-
-        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                // Perform a focus action and check for success.
-                assertTrue(rootLinearLayout.performAction(ACTION_ACCESSIBILITY_FOCUS));
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Refresh the node info.
-        rootLinearLayout.refresh();
-
-        // Check if the node info is focused.
-        assertTrue(rootLinearLayout.isAccessibilityFocused());
-
-        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                // Perform a clear focus action and check for success.
-                assertTrue(rootLinearLayout.performAction(ACTION_CLEAR_ACCESSIBILITY_FOCUS));
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return event.getEventType()
-                        == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Refresh the node info.
-        rootLinearLayout.refresh();
-
-        // Check if the node info is not focused.
-        assertFalse(rootLinearLayout.isAccessibilityFocused());
-    }
-
-    @MediumTest
-    public void testOnlyOneNodeHasAccessibilityFocus() throws Exception {
-        // Get the first not focused edit text.
-        final AccessibilityNodeInfo firstEditText = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.firstEditText)).get(0);
-        assertNotNull(firstEditText);
-        assertTrue(firstEditText.isFocusable());
-        assertTrue(firstEditText.isFocused());
-        assertFalse(firstEditText.isAccessibilityFocused());
-
-        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                // Perform a set focus action and check for success.
-                assertTrue(firstEditText.performAction(ACTION_ACCESSIBILITY_FOCUS));
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Get the second not focused edit text.
-        final AccessibilityNodeInfo secondEditText = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.secondEditText)).get(0);
-        assertNotNull(secondEditText);
-        assertTrue(secondEditText.isFocusable());
-        assertFalse(secondEditText.isFocused());
-        assertFalse(secondEditText.isAccessibilityFocused());
-
-        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                // Perform a set focus action and check for success.
-                assertTrue(secondEditText.performAction(ACTION_ACCESSIBILITY_FOCUS));
-                
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Get the node info again.
-        secondEditText.refresh();
-
-        // Make sure no other node has accessibility focus.
-        AccessibilityNodeInfo root = getInstrumentation().getUiAutomation().getRootInActiveWindow();
-        Queue<AccessibilityNodeInfo> workQueue = new LinkedList<AccessibilityNodeInfo>();
-        workQueue.add(root);
-        while (!workQueue.isEmpty()) {
-            AccessibilityNodeInfo current = workQueue.poll();
-            if (current.isAccessibilityFocused() && !current.equals(secondEditText)) {
-                fail();
-            }
-            final int childCount = current.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                AccessibilityNodeInfo child = current.getChild(i);
-                if (child != null) {
-                    workQueue.offer(child);
-                }
-            }
-        }
-    }
-}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalActivity.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalActivity.java
deleted file mode 100644
index 4a4a4ba..0000000
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalActivity.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * 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 android.accessibilityservice.cts;
-
-import android.os.Bundle;
-
-import com.android.cts.accessibilityservice.R;
-
-/**
- * Activity for testing the accessibility APIs for traversing the
- * text content of a View at several granularities.
- */
-public class AccessibilityTextTraversalActivity extends AccessibilityTestActivity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.accessibility_text_traversal_test);
-    }
-}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
deleted file mode 100644
index cb0877d..0000000
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
+++ /dev/null
@@ -1,4646 +0,0 @@
-/**
- * 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 android.accessibilityservice.cts;
-
-import android.app.UiAutomation;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.text.Selection;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import com.android.cts.accessibilityservice.R;
-
-/**
- * Test cases for testing the accessibility APIs for traversing the text content of
- * a View at several granularities.
- */
-public class AccessibilityTextTraversalTest
-        extends AccessibilityActivityTestCase<AccessibilityTextTraversalActivity>{
-
-    public AccessibilityTextTraversalTest() {
-        super(AccessibilityTextTraversalActivity.class);
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityCharacterOverContentDescription()
-            throws Exception {
-        final View view = getActivity().findViewById(R.id.view);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(View.VISIBLE);
-                view.setContentDescription(getString(R.string.a_b));
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.a_b)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
-                        arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.a_b))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 1
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
-                        arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.a_b))
-                        && event.getFromIndex() == 1
-                        && event.getToIndex() == 2
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
-                        arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.a_b))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
-                arguments));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
-                        arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.a_b))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
-                        arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.a_b))
-                        && event.getFromIndex() == 1
-                        && event.getToIndex() == 2
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
-                        arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.a_b))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 1
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityWordOverContentDescription()
-            throws Exception {
-        final View view = getActivity().findViewById(R.id.view);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(View.VISIBLE);
-                view.setContentDescription(getString(R.string.foo_bar_baz));
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.foo_bar_baz)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 4
-                        && event.getToIndex() == 7
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 8
-                        && event.getToIndex() == 11
-                        && event.getMovementGranularity() ==
-                               AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 8
-                        && event.getToIndex() == 11
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 4
-                        && event.getToIndex() == 7
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(View.class.getName())
-                        && event.getContentDescription().toString().equals(
-                                getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityCharacterOverText()
-            throws Exception {
-        final TextView textView = (TextView) getActivity().findViewById(R.id.text);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                textView.setVisibility(View.VISIBLE);
-                textView.setText(getString(R.string.a_b));
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                       getString(R.string.a_b)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 1
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(1, Selection.getSelectionStart(textView.getText()));
-        assertEquals(1, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 1
-                        && event.getToIndex() == 2
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(textView.getText()));
-        assertEquals(2, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(textView.getText()));
-        assertEquals(3, Selection.getSelectionEnd(textView.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(textView.getText()));
-        assertEquals(3, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(textView.getText()));
-        assertEquals(2, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 1
-                        && event.getToIndex() == 2
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(1, Selection.getSelectionStart(textView.getText()));
-        assertEquals(1, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 1
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(seventhExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(textView.getText()));
-        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(textView.getText()));
-        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityCharacterOverTextExtend()
-            throws Exception {
-        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setVisibility(View.VISIBLE);
-                editText.setText(getString(R.string.a_b));
-                Selection.removeSelection(editText.getText());
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                       getString(R.string.a_b)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-        arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 1
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(1, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 1
-                        && event.getToIndex() == 2
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 1
-                        && event.getToIndex() == 2
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(1, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 1
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Focus the view so we can change selection.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setFocusable(true);
-                editText.requestFocus();
-            }
-        });
-
-        // Put selection at the end of the text.
-        Bundle setSelectionArgs = new Bundle();
-        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 3);
-        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 3);
-        assertTrue(text.performAction(
-                AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(editText.getText()));
-        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
-
-        // Unfocus the view so we can get rid of the soft-keyboard.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.clearFocus();
-                editText.setFocusable(false);
-            }
-        });
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(seventhExpected);
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(editText.getText()));
-        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent eightExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 1
-                        && event.getToIndex() == 2
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(eightExpected);
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(editText.getText()));
-        assertEquals(1, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent ninethExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 1
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(ninethExpected);
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent tenthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 1
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(tenthExpected);
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(editText.getText()));
-        assertEquals(1, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent eleventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 1
-                        && event.getToIndex() == 2
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(eleventhExpected);
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(editText.getText()));
-        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent twelvethExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.a_b))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(twelvethExpected);
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(editText.getText()));
-        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(editText.getText()));
-        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityWordOverText() throws Exception {
-        final TextView textView = (TextView) getActivity().findViewById(R.id.text);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                textView.setVisibility(View.VISIBLE);
-                textView.setText(getString(R.string.foo_bar_baz));
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                       R.string.foo_bar_baz)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(3, Selection.getSelectionStart(textView.getText()));
-        assertEquals(3, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 4
-                        && event.getToIndex() == 7
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(7, Selection.getSelectionStart(textView.getText()));
-        assertEquals(7, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 8
-                        && event.getToIndex() == 11
-                        && event.getMovementGranularity() ==
-                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(textView.getText()));
-        assertEquals(11, Selection.getSelectionEnd(textView.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(textView.getText()));
-        assertEquals(11, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 8
-                        && event.getToIndex() == 11
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Verify the selection position.
-        assertEquals(8, Selection.getSelectionStart(textView.getText()));
-        assertEquals(8, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 4
-                        && event.getToIndex() == 7
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(4, Selection.getSelectionStart(textView.getText()));
-        assertEquals(4, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(textView.getText()));
-        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(textView.getText()));
-        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityWordOverEditTextWithContentDescription()
-            throws Exception {
-        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setVisibility(View.VISIBLE);
-                editText.setText(getString(R.string.foo_bar_baz));
-                editText.setContentDescription(getString(R.string.android_wiki));
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                       R.string.foo_bar_baz)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getContentDescription().equals(getString(R.string.android_wiki))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(3, editText.getSelectionStart());
-        assertEquals(3, editText.getSelectionEnd());
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getContentDescription().equals(getString(R.string.android_wiki))
-                        && event.getFromIndex() == 4
-                        && event.getToIndex() == 7
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(7, editText.getSelectionStart());
-        assertEquals(7, editText.getSelectionEnd());
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getContentDescription().equals(getString(R.string.android_wiki))
-                        && event.getFromIndex() == 8
-                        && event.getToIndex() == 11
-                        && event.getMovementGranularity() ==
-                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(11, editText.getSelectionStart());
-        assertEquals(11, editText.getSelectionEnd());
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(11, editText.getSelectionStart());
-        assertEquals(11, editText.getSelectionEnd());
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getContentDescription().equals(getString(R.string.android_wiki))
-                        && event.getFromIndex() == 8
-                        && event.getToIndex() == 11
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Verify the selection position.
-        assertEquals(8, editText.getSelectionStart());
-        assertEquals(8, editText.getSelectionEnd());
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getContentDescription().equals(getString(R.string.android_wiki))
-                        && event.getFromIndex() == 4
-                        && event.getToIndex() == 7
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(4, editText.getSelectionStart());
-        assertEquals(4, editText.getSelectionEnd());
-
-        // Move to the next character and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getContentDescription().equals(getString(R.string.android_wiki))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, editText.getSelectionStart());
-        assertEquals(0, editText.getSelectionEnd());
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(0, editText.getSelectionStart());
-        assertEquals(0, editText.getSelectionEnd());
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityWordOverTextExtend() throws Exception {
-        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setVisibility(View.VISIBLE);
-                editText.setText(getString(R.string.foo_bar_baz));
-                Selection.removeSelection(editText.getText());
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                       R.string.foo_bar_baz)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-        arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 4
-                        && event.getToIndex() == 7
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(7, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 8
-                        && event.getToIndex() == 11
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(11, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Move to the previous word and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 8
-                        && event.getToIndex() == 11
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(8, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous word and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 4
-                        && event.getToIndex() == 7
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(4, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Focus the view so we can change selection.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setFocusable(true);
-                editText.requestFocus();
-            }
-        });
-
-        // Put selection at the end of the text.
-        Bundle setSelectionArgs = new Bundle();
-        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 11);
-        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 11);
-        assertTrue(text.performAction(
-                AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(editText.getText()));
-        assertEquals(11, Selection.getSelectionEnd(editText.getText()));
-
-        // Unfocus the view so we can get rid of the soft-keyboard.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.clearFocus();
-                editText.setFocusable(false);
-            }
-        });
-
-        // Move to the previous word and wait for an event.
-        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 8
-                        && event.getToIndex() == 11
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(seventhExpected);
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(editText.getText()));
-        assertEquals(8, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous word and wait for an event.
-        AccessibilityEvent eightExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 4
-                        && event.getToIndex() == 7
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(eightExpected);
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(editText.getText()));
-        assertEquals(4, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous character and wait for an event.
-        AccessibilityEvent ninethExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(ninethExpected);
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent tenthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 3
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(tenthExpected);
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(editText.getText()));
-        assertEquals(3, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent eleventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 4
-                        && event.getToIndex() == 7
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(eleventhExpected);
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(editText.getText()));
-        assertEquals(7, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next word and wait for an event.
-        AccessibilityEvent twelvthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
-                        && event.getFromIndex() == 8
-                        && event.getToIndex() == 11
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(twelvthExpected);
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(editText.getText()));
-        assertEquals(11, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(11, Selection.getSelectionStart(editText.getText()));
-        assertEquals(11, Selection.getSelectionEnd(editText.getText()));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityLineOverText() throws Exception {
-        final TextView textView = (TextView) getActivity().findViewById(R.id.text);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                textView.setVisibility(View.VISIBLE);
-                textView.setText(getString(R.string.android_wiki_short));
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                       R.string.android_wiki_short)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-
-        // Move to the next line and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 13
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(13, Selection.getSelectionStart(textView.getText()));
-        assertEquals(13, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next line and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 13
-                        && event.getToIndex() == 25
-                        && event.getMovementGranularity() ==
-                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(25, Selection.getSelectionStart(textView.getText()));
-        assertEquals(25, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next line and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 25
-                        && event.getToIndex() == 34
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(34, Selection.getSelectionStart(textView.getText()));
-        assertEquals(34, Selection.getSelectionEnd(textView.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(34, Selection.getSelectionStart(textView.getText()));
-        assertEquals(34, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the previous line and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 25
-                        && event.getToIndex() == 34
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Verify the selection position.
-        assertEquals(25, Selection.getSelectionStart(textView.getText()));
-        assertEquals(25, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the previous line and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 13
-                        && event.getToIndex() == 25
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(13, Selection.getSelectionStart(textView.getText()));
-        assertEquals(13, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the previous line and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(TextView.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 13
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(textView.getText()));
-        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(textView.getText()));
-        assertEquals(0, Selection.getSelectionEnd(textView.getText()));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityLineOverTextExtend() throws Exception {
-        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setVisibility(View.VISIBLE);
-                editText.setText(getString(R.string.android_wiki_short));
-                Selection.removeSelection(editText.getText());
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                       R.string.android_wiki_short)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-        arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
-
-        // Move to the next line and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 13
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(13, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next line and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 13
-                        && event.getToIndex() == 25
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(25, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next line and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 25
-                        && event.getToIndex() == 34
-                        && event.getMovementGranularity() ==
-                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(34, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous line and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 25
-                        && event.getToIndex() == 34
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(25, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous line and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 13
-                        && event.getToIndex() == 25
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(13, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous line and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                               AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 13
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Focus the view so we can change selection.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setFocusable(true);
-                editText.requestFocus();
-            }
-        });
-
-        // Put selection at the end of the text.
-        Bundle setSelectionArgs = new Bundle();
-        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 34);
-        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 34);
-        assertTrue(text.performAction(
-                AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
-
-        // Verify the selection position.
-        assertEquals(34, Selection.getSelectionStart(editText.getText()));
-        assertEquals(34, Selection.getSelectionEnd(editText.getText()));
-
-        // Unocus the view so we can hide the keyboard.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.clearFocus();
-                editText.setFocusable(false);
-            }
-        });
-
-        // Move to the previous line and wait for an event.
-        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 25
-                        && event.getToIndex() == 34
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(seventhExpected);
-
-        // Verify the selection position.
-        assertEquals(34, Selection.getSelectionStart(editText.getText()));
-        assertEquals(25, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous line and wait for an event.
-        AccessibilityEvent eightExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 13
-                        && event.getToIndex() == 25
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(eightExpected);
-
-        // Verify the selection position.
-        assertEquals(34, Selection.getSelectionStart(editText.getText()));
-        assertEquals(13, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous line and wait for an event.
-        AccessibilityEvent ninethExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                               AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 13
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(ninethExpected);
-
-        // Verify the selection position.
-        assertEquals(34, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(34, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next line and wait for an event.
-        AccessibilityEvent tenthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 13
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(tenthExpected);
-
-        // Verify the selection position.
-        assertEquals(34, Selection.getSelectionStart(editText.getText()));
-        assertEquals(13, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next line and wait for an event.
-        AccessibilityEvent eleventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 13
-                        && event.getToIndex() == 25
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(eleventhExpected);
-
-        // Verify the selection position.
-        assertEquals(34, Selection.getSelectionStart(editText.getText()));
-        assertEquals(25, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next line and wait for an event.
-        AccessibilityEvent twelvethExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_short))
-                        && event.getFromIndex() == 25
-                        && event.getToIndex() == 34
-                        && event.getMovementGranularity() ==
-                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(twelvethExpected);
-
-        // Verify the selection position.
-        assertEquals(34, Selection.getSelectionStart(editText.getText()));
-        assertEquals(34, Selection.getSelectionEnd(editText.getText()));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityPageOverText() throws Exception {
-        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setVisibility(View.VISIBLE);
-                editText.setText(getString(R.string.android_wiki));
-                Selection.removeSelection(editText.getText());
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                       R.string.android_wiki)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        // Move to the next page and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 53
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(53, Selection.getSelectionStart(editText.getText()));
-        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next page and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 53
-                        && event.getToIndex() == 103
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(103, Selection.getSelectionStart(editText.getText()));
-        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next page and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 103
-                        && event.getToIndex() == 153
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(153, Selection.getSelectionStart(editText.getText()));
-        assertEquals(153, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(153, Selection.getSelectionStart(editText.getText()));
-        assertEquals(153, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous page and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 103
-                        && event.getToIndex() == 153
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Verify the selection position.
-        assertEquals(103, Selection.getSelectionStart(editText.getText()));
-        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous page and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 53
-                        && event.getToIndex() == 103
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(53, Selection.getSelectionStart(editText.getText()));
-        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous page and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 53
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityPageOverTextExtend() throws Exception {
-        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setVisibility(View.VISIBLE);
-                editText.setText(getString(R.string.android_wiki));
-                Selection.removeSelection(editText.getText());
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                       R.string.android_wiki)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-        arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
-
-        // Move to the next page and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 53
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next page and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 53
-                        && event.getToIndex() == 103
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next page and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 103
-                        && event.getToIndex() == 153
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(153, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Move to the previous page and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 103
-                        && event.getToIndex() == 153
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous page and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 53
-                        && event.getToIndex() == 103
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous page and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 53
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(0, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Focus the view so we can change selection.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setFocusable(true);
-                editText.requestFocus();
-            }
-        });
-
-        // Put selection at the end of the text.
-        Bundle setSelectionArgs = new Bundle();
-        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 153);
-        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 153);
-        assertTrue(text.performAction(
-                AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
-
-        // Verify the selection position.
-        assertEquals(153, Selection.getSelectionStart(editText.getText()));
-        assertEquals(153, Selection.getSelectionEnd(editText.getText()));
-
-        // Unfocus the view so we can hide the soft-keyboard.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.clearFocus();
-                editText.setFocusable(false);
-            }
-        });
-
-        // Move to the previous page and wait for an event.
-        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 103
-                        && event.getToIndex() == 153
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(seventhExpected);
-
-        // Verify the selection position.
-        assertEquals(153, Selection.getSelectionStart(editText.getText()));
-        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous page and wait for an event.
-        AccessibilityEvent eightExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 53
-                        && event.getToIndex() == 103
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(eightExpected);
-
-        // Verify the selection position.
-        assertEquals(153, Selection.getSelectionStart(editText.getText()));
-        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous page and wait for an event.
-        AccessibilityEvent ninethExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 53
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(ninethExpected);
-
-        // Verify the selection position.
-        assertEquals(153, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(153, Selection.getSelectionStart(editText.getText()));
-        assertEquals(0, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next page and wait for an event.
-        AccessibilityEvent tenthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 0
-                        && event.getToIndex() == 53
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(tenthExpected);
-
-        // Verify the selection position.
-        assertEquals(153, Selection.getSelectionStart(editText.getText()));
-        assertEquals(53, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next page and wait for an event.
-        AccessibilityEvent eleventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 53
-                        && event.getToIndex() == 103
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(eleventhExpected);
-
-        // Verify the selection position.
-        assertEquals(153, Selection.getSelectionStart(editText.getText()));
-        assertEquals(103, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next page and wait for an event.
-        AccessibilityEvent twelvethExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki))
-                        && event.getFromIndex() == 103
-                        && event.getToIndex() == 153
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(twelvethExpected);
-
-        // Verify the selection position.
-        assertEquals(153, Selection.getSelectionStart(editText.getText()));
-        assertEquals(153, Selection.getSelectionEnd(editText.getText()));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityParagraphOverText() throws Exception {
-        final TextView textView = (TextView) getActivity().findViewById(R.id.edit);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                textView.setVisibility(View.VISIBLE);
-                textView.setText(getString(R.string.android_wiki_paragraphs));
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                       R.string.android_wiki_paragraphs)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-
-        // Move to the next paragraph and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 14
-                        && event.getMovementGranularity() ==
-                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(14, Selection.getSelectionStart(textView.getText()));
-        assertEquals(14, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next paragraph and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 16
-                        && event.getToIndex() == 32
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(32, Selection.getSelectionStart(textView.getText()));
-        assertEquals(32, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the next paragraph and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 33
-                        && event.getToIndex() == 47
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(textView.getText()));
-        assertEquals(47, Selection.getSelectionEnd(textView.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(textView.getText()));
-        assertEquals(47, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the previous paragraph and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 33
-                        && event.getToIndex() == 47
-                        && event.getMovementGranularity() ==
-                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Verify the selection position.
-        assertEquals(33, Selection.getSelectionStart(textView.getText()));
-        assertEquals(33, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the previous paragraph and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 16
-                        && event.getToIndex() == 32
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(16, Selection.getSelectionStart(textView.getText()));
-        assertEquals(16, Selection.getSelectionEnd(textView.getText()));
-
-        // Move to the previous paragraph and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 14
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(textView.getText()));
-        assertEquals(2, Selection.getSelectionEnd(textView.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(textView.getText()));
-        assertEquals(2, Selection.getSelectionEnd(textView.getText()));
-    }
-
-    @MediumTest
-    public void testActionNextAndPreviousAtGranularityParagraphOverTextExtend() throws Exception {
-        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setVisibility(View.VISIBLE);
-                editText.setText(getString(R.string.android_wiki_paragraphs));
-                Selection.removeSelection(editText.getText());
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                       R.string.android_wiki_paragraphs)).get(0);
-
-        final int granularities = text.getMovementGranularities();
-        assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
-                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
-
-        final Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
-                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-        arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
-
-        // Move to the next paragraph and wait for an event.
-        AccessibilityEvent firstExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 14
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(firstExpected);
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(editText.getText()));
-        assertEquals(14, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next paragraph and wait for an event.
-        AccessibilityEvent secondExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 16
-                        && event.getToIndex() == 32
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(secondExpected);
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(editText.getText()));
-        assertEquals(32, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next paragraph and wait for an event.
-        AccessibilityEvent thirdExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 33
-                        && event.getToIndex() == 47
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(thirdExpected);
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(editText.getText()));
-        assertEquals(47, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(editText.getText()));
-        assertEquals(47, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous paragraph and wait for an event.
-        AccessibilityEvent fourthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 33
-                        && event.getToIndex() == 47
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fourthExpected);
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(editText.getText()));
-        assertEquals(33, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous paragraph and wait for an event.
-        AccessibilityEvent fifthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 16
-                        && event.getToIndex() == 32
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(fifthExpected);
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(editText.getText()));
-        assertEquals(16, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous paragraph and wait for an event.
-        AccessibilityEvent sixthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 14
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(sixthExpected);
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(editText.getText()));
-        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(2, Selection.getSelectionStart(editText.getText()));
-        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
-
-        // Focus the view so we can change selection.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setFocusable(true);
-                editText.requestFocus();
-            }
-        });
-
-        // Put selection at the end of the text.
-        Bundle setSelectionArgs = new Bundle();
-        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 47);
-        setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 47);
-        assertTrue(text.performAction(
-                AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(editText.getText()));
-        assertEquals(47, Selection.getSelectionEnd(editText.getText()));
-
-        // Unfocus the view so we can get rid of the soft-keyboard.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.clearFocus();
-                editText.setFocusable(false);
-            }
-        });
-
-        // Move to the previous paragraph and wait for an event.
-        AccessibilityEvent seventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 33
-                        && event.getToIndex() == 47
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(seventhExpected);
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(editText.getText()));
-        assertEquals(33, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous paragraph and wait for an event.
-        AccessibilityEvent eightExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 16
-                        && event.getToIndex() == 32
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(eightExpected);
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(editText.getText()));
-        assertEquals(16, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the previous paragraph and wait for an event.
-        AccessibilityEvent ninethExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 14
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(ninethExpected);
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(editText.getText()));
-        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no previous.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(editText.getText()));
-        assertEquals(2, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next paragraph and wait for an event.
-        AccessibilityEvent tenthExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 2
-                        && event.getToIndex() == 14
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(tenthExpected);
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(editText.getText()));
-        assertEquals(14, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next paragraph and wait for an event.
-        AccessibilityEvent eleventhExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 16
-                        && event.getToIndex() == 32
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(eleventhExpected);
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(editText.getText()));
-        assertEquals(32, Selection.getSelectionEnd(editText.getText()));
-
-        // Move to the next paragraph and wait for an event.
-        AccessibilityEvent twlevethExpected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                text.performAction(
-                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return
-                (event.getEventType() ==
-                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
-                        && event.getAction() ==
-                                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-                        && event.getPackageName().equals(getActivity().getPackageName())
-                        && event.getClassName().equals(EditText.class.getName())
-                        && event.getText().size() > 0
-                        && event.getText().get(0).toString().equals(getString(
-                                R.string.android_wiki_paragraphs))
-                        && event.getFromIndex() == 33
-                        && event.getToIndex() == 47
-                        && event.getMovementGranularity() ==
-                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure we got the expected event.
-        assertNotNull(twlevethExpected);
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(editText.getText()));
-        assertEquals(47, Selection.getSelectionEnd(editText.getText()));
-
-        // Make sure there is no next.
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
-
-        // Verify the selection position.
-        assertEquals(47, Selection.getSelectionStart(editText.getText()));
-        assertEquals(47, Selection.getSelectionEnd(editText.getText()));
-    }
-
-    @MediumTest
-    public void testTextEditingActions() throws Exception {
-        if (!getActivity().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_INPUT_METHODS)) {
-            return;
-        }
-
-        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
-        final String textContent = getString(R.string.foo_bar_baz);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                editText.setVisibility(View.VISIBLE);
-                editText.setFocusable(true);
-                editText.requestFocus();
-                editText.setText(getString(R.string.foo_bar_baz));
-                Selection.removeSelection(editText.getText());
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                       getString(R.string.foo_bar_baz)).get(0);
-
-        // Select all text.
-        Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT,
-                editText.getText().length());
-        assertTrue(text.performAction(
-                AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
-
-        // Copy the selected text.
-        text.performAction(AccessibilityNodeInfo.ACTION_COPY);
-
-        // Set selection at the end.
-        final int textLength = editText.getText().length();
-        // Verify the selection position.
-        assertEquals(textLength, Selection.getSelectionStart(editText.getText()));
-        assertEquals(textLength, Selection.getSelectionEnd(editText.getText()));
-
-        // Paste the selected text.
-        assertTrue(text.performAction(
-                AccessibilityNodeInfo.ACTION_PASTE));
-
-        // Verify the content.
-        assertEquals(editText.getText().toString(), textContent + textContent);
-
-        // Select all text.
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT,
-                editText.getText().length());
-        assertTrue(text.performAction(
-                AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
-
-        // Cut the selected text.
-        assertTrue(text.performAction(
-                AccessibilityNodeInfo.ACTION_CUT));
-
-        // Verify the content.
-        assertTrue(TextUtils.isEmpty(editText.getText()));
-    }
-
-    public void testSetSelectionInContentDescription() throws Exception {
-        final View view = getActivity().findViewById(R.id.view);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(View.VISIBLE);
-                view.setContentDescription(getString(R.string.foo_bar_baz));
-            }
-        });
-
-        AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                       getString(R.string.foo_bar_baz)).get(0);
-
-        // Set the cursor position.
-        Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 4);
-        assertTrue(text.performAction(
-                AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
-
-        // Try and fail to set the selection longer than zero.
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 5);
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
-    }
-
-    public void testSelectionPositionForNonEditableView() throws Exception {
-        final View view = getActivity().findViewById(R.id.view);
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(View.VISIBLE);
-                view.setContentDescription(getString(R.string.foo_bar_baz));
-            }
-        });
-
-        final AccessibilityNodeInfo text = getInstrumentation().getUiAutomation()
-               .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                       getString(R.string.foo_bar_baz)).get(0);
-
-        // Check the initial node properties.
-        assertFalse(text.isEditable());
-        assertSame(text.getTextSelectionStart(), -1);
-        assertSame(text.getTextSelectionEnd(), -1);
-
-        // Set the cursor position.
-        getInstrumentation().getUiAutomation().executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                Bundle arguments = new Bundle();
-                arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
-                arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 4);
-                assertTrue(text.performAction(
-                        AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return (event.getEventType()
-                        == AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Refresh the node.
-        AccessibilityNodeInfo refreshedText = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.foo_bar_baz)).get(0);
-
-        // Check the related node properties.
-        assertFalse(refreshedText.isEditable());
-        assertSame(refreshedText.getTextSelectionStart(), 4);
-        assertSame(refreshedText.getTextSelectionEnd(), 4);
-
-        // Try to set to an invalid cursor position.
-        Bundle arguments = new Bundle();
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
-        arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 5);
-        assertFalse(text.performAction(
-                AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
-
-        // Refresh the node.
-        refreshedText = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.foo_bar_baz)).get(0);
-
-        // Check the related node properties.
-        assertFalse(refreshedText.isEditable());
-        assertSame(refreshedText.getTextSelectionStart(), 4);
-        assertSame(refreshedText.getTextSelectionEnd(), 4);
-    }
-}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingActivity.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingActivity.java
deleted file mode 100644
index 6aa4f44..0000000
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingActivity.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * 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 android.accessibilityservice.cts;
-
-import android.os.Bundle;
-
-import com.android.cts.accessibilityservice.R;
-
-/**
- * Activity for testing the accessibility focus APIs exposed to
- * accessibility services. These APIs allow moving accessibility
- * focus in the view tree from an AccessiiblityService. Specifically,
- * this activity is for verifying the hierarchical movement of the
- * accessibility focus.
- */
-public class AccessibilityViewTreeReportingActivity extends AccessibilityTestActivity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.accessibility_view_tree_reporting_test);
-    }
-}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
deleted file mode 100644
index 9785ab4..0000000
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * 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 android.accessibilityservice.cts;
-
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import com.android.cts.accessibilityservice.R;
-
-/**
- * Test cases for testing the accessibility focus APIs exposed to accessibility
- * services. This test checks how the view hierarchy is reported to accessibility
- * services.
- */
-public class AccessibilityViewTreeReportingTest
-        extends AccessibilityActivityTestCase<AccessibilityViewTreeReportingActivity>{
-
-    public AccessibilityViewTreeReportingTest() {
-        super(AccessibilityViewTreeReportingActivity.class);
-    }
-
-    @MediumTest
-    public void testDescendantsOfNotImportantViewReportedInOrder1() throws Exception {
-        AccessibilityNodeInfo firstFrameLayout = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.firstFrameLayout)).get(0);
-        assertNotNull(firstFrameLayout);
-        assertSame(3, firstFrameLayout.getChildCount());
-
-        // Check if the first child is the right one.
-        AccessibilityNodeInfo firstTextView = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                    R.string.firstTextView)).get(0);
-        assertEquals(firstTextView, firstFrameLayout.getChild(0));
-
-        // Check if the second child is the right one.
-        AccessibilityNodeInfo firstEditText = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
-                    R.string.firstEditText)).get(0);
-        assertEquals(firstEditText, firstFrameLayout.getChild(1));
-
-        // Check if the third child is the right one.
-        AccessibilityNodeInfo firstButton = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.firstButton)).get(0);
-        assertEquals(firstButton, firstFrameLayout.getChild(2));
-    }
-
-    @MediumTest
-    public void testDescendantsOfNotImportantViewReportedInOrder2() throws Exception {
-        AccessibilityNodeInfo secondFrameLayout = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.secondFrameLayout)).get(0);
-        assertNotNull(secondFrameLayout);
-        assertSame(3, secondFrameLayout.getChildCount());
-
-        // Check if the first child is the right one.
-        AccessibilityNodeInfo secondTextView = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.secondTextView)).get(0);
-        assertEquals(secondTextView, secondFrameLayout.getChild(0));
-
-        // Check if the second child is the right one.
-        AccessibilityNodeInfo secondEditText = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.secondEditText)).get(0);
-        assertEquals(secondEditText, secondFrameLayout.getChild(1));
-
-        // Check if the third child is the right one.
-        AccessibilityNodeInfo secondButton = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.secondButton)).get(0);
-        assertEquals(secondButton, secondFrameLayout.getChild(2));
-    }
-
-    @MediumTest
-    public void testDescendantsOfNotImportantViewReportedInOrder3() throws Exception {
-        AccessibilityNodeInfo rootLinearLayout = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.rootLinearLayout)).get(0);
-        assertNotNull(rootLinearLayout);
-        assertSame(4, rootLinearLayout.getChildCount());
-
-        // Check if the first child is the right one.
-        AccessibilityNodeInfo firstFrameLayout = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.firstFrameLayout)).get(0);
-        assertEquals(firstFrameLayout, rootLinearLayout.getChild(0));
-
-        // Check if the second child is the right one.
-        AccessibilityNodeInfo secondTextView = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.secondTextView)).get(0);
-        assertEquals(secondTextView, rootLinearLayout.getChild(1));
-
-        // Check if the third child is the right one.
-        AccessibilityNodeInfo secondEditText = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.secondEditText)).get(0);
-        assertEquals(secondEditText, rootLinearLayout.getChild(2));
-
-        // Check if the fourth child is the right one.
-        AccessibilityNodeInfo secondButton = getInstrumentation().getUiAutomation()
-            .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                    getString(R.string.secondButton)).get(0);
-        assertEquals(secondButton, rootLinearLayout.getChild(3));
-    }
-}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivity.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivity.java
deleted file mode 100644
index aa66a45..0000000
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivity.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * 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 android.accessibilityservice.cts;
-
-import android.os.Bundle;
-import android.view.View;
-
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import com.android.cts.accessibilityservice.R;
-
-/**
- * Activity for testing the accessibility APIs for querying of
- * the screen content. These APIs allow exploring the screen and
- * requesting an action to be performed on a given view from an
- * AccessibilityService.
- */
-public class AccessibilityWindowQueryActivity extends AccessibilityTestActivity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.query_window_test);
-
-        findViewById(R.id.button5).setOnClickListener(new View.OnClickListener() {
-            public void onClick(View v) {
-                /* do nothing */
-            }
-        });
-        findViewById(R.id.button5).setOnLongClickListener(new View.OnLongClickListener() {
-            public boolean onLongClick(View v) {
-                return true;
-            }
-        });
-
-        findViewById(R.id.button5).setAccessibilityDelegate(new View.AccessibilityDelegate() {
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-                super.onInitializeAccessibilityNodeInfo(host, info);
-                info.addAction(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
-            }
-
-            @Override
-            public boolean performAccessibilityAction(View host, int action, Bundle args) {
-                if (action == R.id.foo_custom_action) {
-                    return true;
-                }
-                return super.performAccessibilityAction(host, action, args);
-            }
-        });
-    }
-}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
deleted file mode 100644
index f8cf4dd..0000000
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ /dev/null
@@ -1,894 +0,0 @@
-/*
- * 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 android.accessibilityservice.cts;
-
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT;
-
-import android.accessibilityservice.AccessibilityService;
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.app.UiAutomation;
-import android.graphics.Rect;
-import android.os.SystemClock;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.Gravity;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import android.view.accessibility.AccessibilityWindowInfo;
-
-import android.widget.Button;
-import com.android.cts.accessibilityservice.R;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Test cases for testing the accessibility APIs for querying of the screen content.
- * These APIs allow exploring the screen and requesting an action to be performed
- * on a given view from an AccessibilityService.
- */
-public class AccessibilityWindowQueryTest
-        extends AccessibilityActivityTestCase<AccessibilityWindowQueryActivity> {
-
-    private static final long TIMEOUT_WINDOW_STATE_IDLE = 500;
-
-    public AccessibilityWindowQueryTest() {
-        super(AccessibilityWindowQueryActivity.class);
-    }
-
-    @MediumTest
-    public void testFindByText() throws Exception {
-        // find a view by text
-        List<AccessibilityNodeInfo> buttons = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText("b");
-        assertEquals(9, buttons.size());
-    }
-
-    @MediumTest
-    public void testFindByContentDescription() throws Exception {
-        // find a view by text
-        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.contentDescription)).get(0);
-        assertNotNull(button);
-    }
-
-    @MediumTest
-    public void testTraverseWindow() throws Exception {
-        verifyNodesInAppWindow(getInstrumentation().getUiAutomation().getRootInActiveWindow());
-    }
-
-    @MediumTest
-    public void testNoWindowsAccessIfFlagNotSet() throws Exception {
-        // Make sure the windows cannot be accessed.
-        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-        assertTrue(uiAutomation.getWindows().isEmpty());
-
-        // Find a button to click on.
-        final AccessibilityNodeInfo button1 = uiAutomation.getRootInActiveWindow()
-                .findAccessibilityNodeInfosByViewId(
-                        "com.android.cts.accessibilityservice:id/button1").get(0);
-
-        // Argh...
-        final List<AccessibilityEvent> events = new ArrayList<AccessibilityEvent>();
-
-        // Click the button.
-        uiAutomation.executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                button1.performAction(AccessibilityNodeInfo.ACTION_CLICK);
-            }
-        },
-        new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
-                    events.add(event);
-                    return true;
-                }
-                return false;
-            }
-        },
-        TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure the source window cannot be accessed.
-        AccessibilityEvent event = events.get(0);
-        assertNull(event.getSource().getWindow());
-    }
-
-    @MediumTest
-    public void testTraverseAllWindows() throws Exception {
-        setAccessInteractiveWindowsFlag();
-        try {
-            UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-
-            List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
-            Rect boundsInScreen = new Rect();
-
-            final int windowCount = windows.size();
-            for (int i = 0; i < windowCount; i++) {
-                AccessibilityWindowInfo window = windows.get(i);
-
-                window.getBoundsInScreen(boundsInScreen);
-                assertFalse(boundsInScreen.isEmpty()); // Varies on screen size, emptiness check.
-                assertNull(window.getParent());
-                assertSame(0, window.getChildCount());
-                assertNull(window.getParent());
-                assertNotNull(window.getRoot());
-
-                if (window.getType() == AccessibilityWindowInfo.TYPE_APPLICATION) {
-                    assertTrue(window.isFocused());
-                    assertTrue(window.isActive());
-                    verifyNodesInAppWindow(window.getRoot());
-                } else if (window.getType() == AccessibilityWindowInfo.TYPE_SYSTEM) {
-                    assertFalse(window.isFocused());
-                    assertFalse(window.isActive());
-                }
-            }
-        } finally {
-            clearAccessInteractiveWindowsFlag();
-        }
-    }
-
-    @MediumTest
-    public void testTraverseWindowFromEvent() throws Exception {
-        setAccessInteractiveWindowsFlag();
-        try {
-            UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-
-            // Find a button to click on.
-            final AccessibilityNodeInfo button1 = uiAutomation.getRootInActiveWindow()
-                    .findAccessibilityNodeInfosByViewId(
-                            "com.android.cts.accessibilityservice:id/button1").get(0);
-
-            // Argh...
-            final List<AccessibilityEvent> events = new ArrayList<AccessibilityEvent>();
-
-            // Click the button.
-            uiAutomation.executeAndWaitForEvent(new Runnable() {
-                @Override
-                public void run() {
-                    button1.performAction(AccessibilityNodeInfo.ACTION_CLICK);
-                }
-            },
-            new UiAutomation.AccessibilityEventFilter() {
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
-                        events.add(event);
-                        return true;
-                    }
-                    return false;
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-
-            // Get the source window.
-            AccessibilityEvent event = events.get(0);
-            AccessibilityWindowInfo window = event.getSource().getWindow();
-
-            // Verify the application window.
-            Rect boundsInScreen = new Rect();
-            window.getBoundsInScreen(boundsInScreen);
-            assertFalse(boundsInScreen.isEmpty()); // Varies on screen size, so just emptiness check.
-            assertSame(window.getType(), AccessibilityWindowInfo.TYPE_APPLICATION);
-            assertTrue(window.isFocused());
-            assertTrue(window.isActive());
-            assertNull(window.getParent());
-            assertSame(0, window.getChildCount());
-            assertNotNull(window.getRoot());
-
-            // Verify the window content.
-            verifyNodesInAppWindow(window.getRoot());
-        } finally {
-            clearAccessInteractiveWindowsFlag();
-        }
-    }
-
-    @MediumTest
-    public void testInteractWithAppWindow() throws Exception {
-        setAccessInteractiveWindowsFlag();
-        try {
-            UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-
-            // Find a button to click on.
-            final AccessibilityNodeInfo button1 = uiAutomation.getRootInActiveWindow()
-                    .findAccessibilityNodeInfosByViewId(
-                            "com.android.cts.accessibilityservice:id/button1").get(0);
-
-            // Argh...
-            final List<AccessibilityEvent> events = new ArrayList<AccessibilityEvent>();
-
-            // Click the button.
-            uiAutomation.executeAndWaitForEvent(new Runnable() {
-                @Override
-                public void run() {
-                    button1.performAction(AccessibilityNodeInfo.ACTION_CLICK);
-                }
-            },
-            new UiAutomation.AccessibilityEventFilter() {
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
-                        events.add(event);
-                        return true;
-                    }
-                    return false;
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-
-            // Get the source window.
-            AccessibilityEvent event = events.get(0);
-            AccessibilityWindowInfo window = event.getSource().getWindow();
-
-            // Find a another button from the event's window.
-            final AccessibilityNodeInfo button2 = window.getRoot()
-                    .findAccessibilityNodeInfosByViewId(
-                            "com.android.cts.accessibilityservice:id/button2").get(0);
-
-            // Click the second button.
-            uiAutomation.executeAndWaitForEvent(new Runnable() {
-                @Override
-                public void run() {
-                    button2.performAction(AccessibilityNodeInfo.ACTION_CLICK);
-                }
-            },
-            new UiAutomation.AccessibilityEventFilter() {
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED;
-                }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-        } finally {
-            clearAccessInteractiveWindowsFlag();
-        }
-    }
-
-    @MediumTest
-    public void testSingleAccessibilityFocusAcrossWindows() throws Exception {
-        setAccessInteractiveWindowsFlag();
-        try {
-            // Add two more windows.
-            addTwoAppPanelWindows();
-
-            // Put accessibility focus in the first app window.
-            ensureAppWindowFocusedOrFail(0);
-            // Make sure there only one accessibility focus.
-            assertSingleAccessibilityFocus();
-
-            // Put accessibility focus in the second app window.
-            ensureAppWindowFocusedOrFail(1);
-            // Make sure there only one accessibility focus.
-            assertSingleAccessibilityFocus();
-
-            // Put accessibility focus in the third app window.
-            ensureAppWindowFocusedOrFail(2);
-            // Make sure there only one accessibility focus.
-            assertSingleAccessibilityFocus();
-        } finally {
-            ensureAccessibilityFocusCleared();
-            clearAccessInteractiveWindowsFlag();
-        }
-    }
-
-    @MediumTest
-    public void testPerformActionFocus() throws Exception {
-        // find a view and make sure it is not focused
-        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.button5)).get(0);
-        assertFalse(button.isFocused());
-
-        // focus the view
-        assertTrue(button.performAction(ACTION_FOCUS));
-
-        // find the view again and make sure it is focused
-        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
-                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
-        assertTrue(button.isFocused());
-    }
-
-    @MediumTest
-    public void testPerformActionClearFocus() throws Exception {
-        // find a view and make sure it is not focused
-        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.button5)).get(0);
-        assertFalse(button.isFocused());
-
-        // focus the view
-        assertTrue(button.performAction(ACTION_FOCUS));
-
-        // find the view again and make sure it is focused
-        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
-                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
-        assertTrue(button.isFocused());
-
-        // unfocus the view
-        assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
-
-        // find the view again and make sure it is not focused
-        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
-                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
-        assertFalse(button.isFocused());
-    }
-
-    @MediumTest
-    public void testPerformActionSelect() throws Exception {
-        // find a view and make sure it is not selected
-        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.button5)).get(0);
-        assertFalse(button.isSelected());
-
-        // select the view
-        assertTrue(button.performAction(ACTION_SELECT));
-
-        // find the view again and make sure it is selected
-        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
-                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
-        assertTrue(button.isSelected());
-    }
-
-    @MediumTest
-    public void testPerformActionClearSelection() throws Exception {
-        // find a view and make sure it is not selected
-        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.button5)).get(0);
-        assertFalse(button.isSelected());
-
-        // select the view
-        assertTrue(button.performAction(ACTION_SELECT));
-
-        // find the view again and make sure it is selected
-        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
-                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
-
-        assertTrue(button.isSelected());
-
-        // unselect the view
-        assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
-
-        // find the view again and make sure it is not selected
-        button = getInstrumentation().getUiAutomation().getRootInActiveWindow()
-                .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0);
-        assertFalse(button.isSelected());
-    }
-
-    @MediumTest
-    public void testPerformActionClick() throws Exception {
-        // find a view and make sure it is not selected
-        final AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.button5)).get(0);
-        assertFalse(button.isSelected());
-
-        // Make an action and wait for an event.
-        AccessibilityEvent expected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                button.performAction(ACTION_CLICK);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED);
-            }
-        },
-        TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure the expected event was received.
-        assertNotNull(expected);
-    }
-
-    @MediumTest
-    public void testPerformActionLongClick() throws Exception {
-        // find a view and make sure it is not selected
-        final AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.button5)).get(0);
-        assertFalse(button.isSelected());
-
-        // Make an action and wait for an event.
-        AccessibilityEvent expected = getInstrumentation().getUiAutomation()
-                .executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                button.performAction(ACTION_LONG_CLICK);
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
-            }
-        },
-        TIMEOUT_ASYNC_PROCESSING);
-
-        // Make sure the expected event was received.
-        assertNotNull(expected);
-    }
-
-
-    @MediumTest
-    public void testPerformCustomAction() throws Exception {
-        // find a view and make sure it is not selected
-        AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.button5)).get(0);
-
-        // find the custom action and perform it
-        List<AccessibilityAction> actions = button.getActionList();
-        final int actionCount = actions.size();
-        for (int i = 0; i < actionCount; i++) {
-            AccessibilityAction action = actions.get(i);
-            if (action.getId() == R.id.foo_custom_action) {
-                assertSame(action.getLabel(), "Foo");
-                // perform the action
-                assertTrue(button.performAction(action.getId()));
-                return;
-            }
-        }
-    }
-
-    @MediumTest
-    public void testGetEventSource() throws Exception {
-        // find a view and make sure it is not focused
-        final AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
-                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                        getString(R.string.button5)).get(0);
-        assertFalse(button.isSelected());
-
-        // focus and wait for the event
-        AccessibilityEvent awaitedEvent = getInstrumentation().getUiAutomation()
-            .executeAndWaitForEvent(
-                new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(button.performAction(ACTION_FOCUS));
-            }
-        },
-                new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED);
-            }
-        },
-        TIMEOUT_ASYNC_PROCESSING);
-
-        assertNotNull(awaitedEvent);
-
-        // check that last event source
-        AccessibilityNodeInfo source = awaitedEvent.getSource();
-        assertNotNull(source);
-
-        // bounds
-        Rect buttonBounds = new Rect();
-        button.getBoundsInParent(buttonBounds);
-        Rect sourceBounds = new Rect();
-        source.getBoundsInParent(sourceBounds);
-
-        assertEquals(buttonBounds.left, sourceBounds.left);
-        assertEquals(buttonBounds.right, sourceBounds.right);
-        assertEquals(buttonBounds.top, sourceBounds.top);
-        assertEquals(buttonBounds.bottom, sourceBounds.bottom);
-
-        // char sequence attributes
-        assertEquals(button.getPackageName(), source.getPackageName());
-        assertEquals(button.getClassName(), source.getClassName());
-        assertEquals(button.getText().toString(), source.getText().toString());
-        assertSame(button.getContentDescription(), source.getContentDescription());
-
-        // boolean attributes
-        assertSame(button.isFocusable(), source.isFocusable());
-        assertSame(button.isClickable(), source.isClickable());
-        assertSame(button.isEnabled(), source.isEnabled());
-        assertNotSame(button.isFocused(), source.isFocused());
-        assertSame(button.isLongClickable(), source.isLongClickable());
-        assertSame(button.isPassword(), source.isPassword());
-        assertSame(button.isSelected(), source.isSelected());
-        assertSame(button.isCheckable(), source.isCheckable());
-        assertSame(button.isChecked(), source.isChecked());
-    }
-
-    @MediumTest
-    public void testPerformGlobalActionBack() throws Exception {
-        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_BACK));
-
-        // Sleep a bit so the UI is settles.
-        waitForIdle();
-    }
-
-    @MediumTest
-    public void testPerformGlobalActionHome() throws Exception {
-        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_HOME));
-
-        // Sleep a bit so the UI is settles.
-        waitForIdle();
-    }
-
-    @MediumTest
-    public void testPerformGlobalActionRecents() throws Exception {
-        // Check whether the action succeeded.
-        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_RECENTS));
-
-        // Sleep a bit so the UI is settles.
-        waitForIdle();
-
-        // This is a necessary since the back action does not
-        // dismiss recents until they stop animating. Sigh...
-        SystemClock.sleep(5000);
-
-        // Clean up.
-        getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_BACK);
-
-        // Sleep a bit so the UI is settles.
-        waitForIdle();
-    }
-
-    @MediumTest
-    public void testPerformGlobalActionNotifications() throws Exception {
-        // Perform the action under test
-        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS));
-
-        // Sleep a bit so the UI is settles.
-        waitForIdle();
-
-        // Clean up.
-        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_BACK));
-
-        // Sleep a bit so the UI is settles.
-        waitForIdle();
-    }
-
-    @MediumTest
-    public void testPerformGlobalActionQuickSettings() throws Exception {
-        // Check whether the action succeeded.
-        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS));
-
-        // Sleep a bit so the UI is settles.
-        waitForIdle();
-
-        // Clean up.
-        getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_BACK);
-
-        // Sleep a bit so the UI is settles.
-        waitForIdle();
-    }
-
-    @MediumTest
-    public void testPerformGlobalActionPowerDialog() throws Exception {
-        // Check whether the action succeeded.
-        assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_POWER_DIALOG));
-
-        // Sleep a bit so the UI is settles.
-        waitForIdle();
-
-        // Clean up.
-        getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_BACK);
-
-        // Sleep a bit so the UI is settles.
-        waitForIdle();
-    }
-
-    @MediumTest
-    public void testObjectContract() throws Exception {
-        try {
-            AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
-            info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
-            getInstrumentation().getUiAutomation().setServiceInfo(info);
-
-            // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = getInstrumentation().getUiAutomation()
-                    .getRootInActiveWindow().findAccessibilityNodeInfosByText(
-                            getString(R.string.button5)).get(0);
-            AccessibilityNodeInfo parent = button.getParent();
-            final int childCount = parent.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                AccessibilityNodeInfo child = parent.getChild(i);
-                assertNotNull(child);
-                if (child.equals(button)) {
-                    assertEquals("Equal objects must have same hasCode.", button.hashCode(),
-                            child.hashCode());
-                    return;
-                }
-            }
-            fail("Parent's children do not have the info whose parent is the parent.");
-        } finally {
-            AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
-            info.flags &= ~AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
-            getInstrumentation().getUiAutomation().setServiceInfo(info);
-        }
-    }
-
-    private void assertSingleAccessibilityFocus() {
-        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-        List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
-        AccessibilityWindowInfo focused = null;
-
-        final int windowCount = windows.size();
-        for (int i = 0; i < windowCount; i++) {
-            AccessibilityWindowInfo window = windows.get(i);
-
-            if (window.isAccessibilityFocused()) {
-                if (focused == null) {
-                    focused = window;
-
-                    AccessibilityNodeInfo root = window.getRoot();
-                    assertEquals(uiAutomation.findFocus(
-                            AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), root);
-                    assertEquals(root.findFocus(
-                            AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), root);
-                } else {
-                    throw new AssertionError("Duplicate accessibility focus");
-                }
-            } else {
-                assertNull(window.getRoot().findFocus(
-                        AccessibilityNodeInfo.FOCUS_ACCESSIBILITY));
-            }
-        }
-    }
-
-    private void ensureAppWindowFocusedOrFail(int appWindowIndex) throws TimeoutException {
-        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-        List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
-        AccessibilityWindowInfo focusTareget = null;
-
-        int visitedAppWindows = -1;
-        final int windowCount = windows.size();
-        for (int i = 0; i < windowCount; i++) {
-            AccessibilityWindowInfo window = windows.get(i);
-            if (window.getType() == AccessibilityWindowInfo.TYPE_APPLICATION) {
-                visitedAppWindows++;
-                if (appWindowIndex <= visitedAppWindows) {
-                    focusTareget = window;
-                    break;
-                }
-            }
-        }
-
-        if (focusTareget == null) {
-            throw new IllegalStateException("Couldn't find app window: " + appWindowIndex);
-        }
-
-        if (focusTareget.isAccessibilityFocused()) {
-            return;
-        }
-
-        final AccessibilityWindowInfo finalFocusTarget = focusTareget;
-        uiAutomation.executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(finalFocusTarget.getRoot().performAction(
-                        AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS));
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        windows = uiAutomation.getWindows();
-        for (int i = 0; i < windowCount; i++) {
-            AccessibilityWindowInfo window = windows.get(i);
-            if (window.getId() == focusTareget.getId()) {
-                assertTrue(window.isAccessibilityFocused());
-                break;
-            }
-        }
-    }
-
-    private void addTwoAppPanelWindows() throws TimeoutException {
-        final UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-
-        uiAutomation.waitForIdle(TIMEOUT_WINDOW_STATE_IDLE, TIMEOUT_ASYNC_PROCESSING);
-
-        // Add the first window.
-        uiAutomation.executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                getInstrumentation().runOnMainSync(new Runnable() {
-                    @Override
-                    public void run() {
-                        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
-                        params.gravity = Gravity.TOP;
-                        params.width = WindowManager.LayoutParams.MATCH_PARENT;
-                        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
-                        params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-                                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-                        params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-                        params.token = getActivity().getWindow().getDecorView().getWindowToken();
-
-                        Button button = new Button(getActivity());
-                        button.setText(R.string.button1);
-                        getActivity().getWindowManager().addView(button, params);
-                    }
-                });
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-
-        // Add the second window.
-        uiAutomation.executeAndWaitForEvent(new Runnable() {
-            @Override
-            public void run() {
-                getInstrumentation().runOnMainSync(new Runnable() {
-                    @Override
-                    public void run() {
-                        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
-                        params.gravity = Gravity.BOTTOM;
-                        params.width = WindowManager.LayoutParams.MATCH_PARENT;
-                        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
-                        params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-                                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-                        params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-                        params.token = getActivity().getWindow().getDecorView().getWindowToken();
-
-                        Button button = new Button(getActivity());
-                        button.setText(R.string.button2);
-                        getActivity().getWindowManager().addView(button, params);
-                    }
-                });
-            }
-        }, new UiAutomation.AccessibilityEventFilter() {
-            @Override
-            public boolean accept(AccessibilityEvent event) {
-                return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
-            }
-        }, TIMEOUT_ASYNC_PROCESSING);
-    }
-
-    private void setAccessInteractiveWindowsFlag () {
-        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-        AccessibilityServiceInfo info = uiAutomation.getServiceInfo();
-        info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
-        uiAutomation.setServiceInfo(info);
-    }
-
-    private void clearAccessInteractiveWindowsFlag () {
-        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-        AccessibilityServiceInfo info = uiAutomation.getServiceInfo();
-        info.flags &= ~AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
-        uiAutomation.setServiceInfo(info);
-    }
-
-    private void ensureAccessibilityFocusCleared() {
-        try {
-            final UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-            uiAutomation.executeAndWaitForEvent(new Runnable() {
-                @Override
-                public void run() {
-                    List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
-                    final int windowCount = windows.size();
-                    for (int i = 0; i < windowCount; i++) {
-                        AccessibilityWindowInfo window = windows.get(i);
-                        if (window.isAccessibilityFocused()) {
-                            window.getRoot().performAction(
-                                    AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
-                        }
-                    }
-                }
-            }, new UiAutomation.AccessibilityEventFilter() {
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return event.getEventType() ==
-                            AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
-                }
-            }, TIMEOUT_ASYNC_PROCESSING);
-        } catch (TimeoutException te) {
-            /* ignore */
-        }
-    }
-
-    private void verifyNodesInAppWindow(AccessibilityNodeInfo root) throws Exception {
-        try {
-            AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
-            info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
-            getInstrumentation().getUiAutomation().setServiceInfo(info);
-
-            root.refresh();
-
-            // make list of expected nodes
-            List<String> classNameAndTextList = new ArrayList<String>();
-            classNameAndTextList.add("android.widget.LinearLayout");
-            classNameAndTextList.add("android.widget.LinearLayout");
-            classNameAndTextList.add("android.widget.LinearLayout");
-            classNameAndTextList.add("android.widget.LinearLayout");
-            classNameAndTextList.add("android.widget.ButtonB1");
-            classNameAndTextList.add("android.widget.ButtonB2");
-            classNameAndTextList.add("android.widget.ButtonB3");
-            classNameAndTextList.add("android.widget.ButtonB4");
-            classNameAndTextList.add("android.widget.ButtonB5");
-            classNameAndTextList.add("android.widget.ButtonB6");
-            classNameAndTextList.add("android.widget.ButtonB7");
-            classNameAndTextList.add("android.widget.ButtonB8");
-            classNameAndTextList.add("android.widget.ButtonB9");
-
-            String contentViewIdResName = "com.android.cts.accessibilityservice:id/added_content";
-            boolean verifyContent = false;
-
-            Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
-            fringe.add(root);
-
-            // do a BFS traversal and check nodes
-            while (!fringe.isEmpty()) {
-                AccessibilityNodeInfo current = fringe.poll();
-
-                if (!verifyContent
-                        && contentViewIdResName.equals(current.getViewIdResourceName())) {
-                    verifyContent = true;
-                }
-
-                if (verifyContent) {
-                    CharSequence text = current.getText();
-                    String receivedClassNameAndText = current.getClassName().toString()
-                            + ((text != null) ? text.toString() : "");
-                    String expectedClassNameAndText = classNameAndTextList.remove(0);
-
-                    assertEquals("Did not get the expected node info",
-                            expectedClassNameAndText, receivedClassNameAndText);
-                }
-
-                final int childCount = current.getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    AccessibilityNodeInfo child = current.getChild(i);
-                    fringe.add(child);
-                }
-            }
-        } finally {
-            AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
-            info.flags &= ~AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
-            getInstrumentation().getUiAutomation().setServiceInfo(info);
-        }
-    }
-
-    @Override
-    protected void scrubClass(Class<?> testCaseClass) {
-        /* intentionally do not scrub */
-    }
-}
diff --git a/tests/tests/accounts/Android.mk b/tests/tests/accounts/Android.mk
index 6ed35c6..4e56984 100644
--- a/tests/tests/accounts/Android.mk
+++ b/tests/tests/accounts/Android.mk
@@ -29,5 +29,10 @@
 
 LOCAL_SDK_VERSION := current
 
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/accounts/AndroidManifest.xml b/tests/tests/accounts/AndroidManifest.xml
index d882690..0d4a534 100644
--- a/tests/tests/accounts/AndroidManifest.xml
+++ b/tests/tests/accounts/AndroidManifest.xml
@@ -36,6 +36,8 @@
         <activity android:name="android.accounts.cts.AccountRemovalDummyActivity" >
         </activity>
 
+        <activity android:name="android.accounts.cts.AccountAuthenticatorDummyActivity" />
+
         <service android:name="MockAccountService" android:exported="true"
                  android:process="android.accounts.cts">
             <intent-filter>
diff --git a/tests/tests/accounts/AndroidTest.xml b/tests/tests/accounts/AndroidTest.xml
index 3e29c9c..c15cdce 100644
--- a/tests/tests/accounts/AndroidTest.xml
+++ b/tests/tests/accounts/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,7 +13,14 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Test module config for Account apis">
-    <include name="common-config" />
-    <option name="cts-apk-installer:test-file-name" value="CtsUnaffiliatedAccountAuthenticators.apk" />
-</configuration>
+<configuration description="Config for CTS Accounts test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsUnaffiliatedAccountAuthenticators.apk" />
+        <option name="test-file-name" value="CtsAccountManagerTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.accounts.cts" />
+        <option name="runtime-hint" value="1m25s" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.mk b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.mk
index cb504da..3e43eee 100644
--- a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.mk
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_SDK_VERSION := current
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-        ctstestrunner \
+	ctstestrunner \
 	CtsAccountTestsCommon
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -35,6 +35,9 @@
 
 LOCAL_PACKAGE_NAME := CtsUnaffiliatedAccountAuthenticators
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml
index c32f89f..3708d83 100644
--- a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml
@@ -41,15 +41,15 @@
             <meta-data android:name="android.accounts.AccountAuthenticator"
                        android:resource="@xml/standard_authenticator" />
         </service>
-<!--
-        <service android:name=".CustomAccountAuthService" android:exported="false">
+
+        <service android:name=".CustomAccountAuthService"
+                 android:exported="false">
             <intent-filter>
                 <action android:name="android.accounts.AccountAuthenticator" />
             </intent-filter>
             <meta-data android:name="android.accounts.AccountAuthenticator"
                        android:resource="@xml/custom_authenticator" />
         </service>
-        -->
 
     </application>
 </manifest>
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/custom_authenticator.xml b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/custom_authenticator.xml
index 3485f76..35b557a 100644
--- a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/custom_authenticator.xml
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/custom_authenticator.xml
@@ -21,7 +21,7 @@
 <!-- for the Account Manager. -->
 
 <account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:accountType="android.accounts.test.custom"
+    android:accountType="android.accounts.test.custom.unaffiliated"
     android:icon="@drawable/ic_cts_selected_custom_account"
     android:smallIcon="@drawable/ic_cts_minitab_selected_custom_account"
     android:customTokens="true"
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/src/android/accounts/cts/unaffiliated/CustomAccountAuthService.java b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/src/android/accounts/cts/unaffiliated/CustomAccountAuthService.java
new file mode 100644
index 0000000..0d32e2f
--- /dev/null
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/src/android/accounts/cts/unaffiliated/CustomAccountAuthService.java
@@ -0,0 +1,21 @@
+package android.accounts.cts.unaffiliated;
+
+import android.accounts.cts.common.Fixtures;
+import android.accounts.cts.common.CustomTestAccountAuthenticator;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * a basic Mock Service for wrapping the CustomAccountAuthenticator.
+ */
+public class CustomAccountAuthService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        CustomTestAccountAuthenticator auth = new CustomTestAccountAuthenticator(this,
+                Fixtures.TYPE_CUSTOM_UNAFFILIATED);
+        return auth.getIBinder();
+    }
+}
+
diff --git a/tests/tests/accounts/OldAndroidTest.xml b/tests/tests/accounts/OldAndroidTest.xml
new file mode 100644
index 0000000..3e29c9c
--- /dev/null
+++ b/tests/tests/accounts/OldAndroidTest.xml
@@ -0,0 +1,18 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Test module config for Account apis">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsUnaffiliatedAccountAuthenticators.apk" />
+</configuration>
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/CustomTestAccountAuthenticator.java b/tests/tests/accounts/common/src/android/accounts/cts/common/CustomTestAccountAuthenticator.java
new file mode 100644
index 0000000..48726a5
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/CustomTestAccountAuthenticator.java
@@ -0,0 +1,174 @@
+package android.accounts.cts.common;
+
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Subclass of {@link TestAccountAuthenticator} with startAddAccountSession(...)
+ * and startUpdateCredentialsSession(...) overridden but not finishSession(...)..
+ */
+public class CustomTestAccountAuthenticator extends TestAccountAuthenticator {
+
+    private final AtomicInteger mTokenCounter = new AtomicInteger(0);
+    private final String mAccountType;
+    private final Context mContext;
+
+    /**
+     * @param context
+     * @param accountType
+     */
+    public CustomTestAccountAuthenticator(Context context, String accountType) {
+        super(context, accountType);
+        mAccountType = accountType;
+        mContext = context;
+    }
+
+    /**
+     * Starts add account flow of the specified accountType to authenticate user.
+     */
+    @Override
+    public Bundle startAddAccountSession(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+
+        if (!mAccountType.equals(accountType)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        String accountName = null;
+        boolean isCallbackRequired = false;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+            isCallbackRequired = options.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+            sessionBundle = options.getBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+        }
+
+        Bundle result = new Bundle();
+        String statusToken = Fixtures.PREFIX_STATUS_TOKEN + accountName;
+        String password = Fixtures.PREFIX_PASSWORD + accountName;
+        if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+            result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN, statusToken);
+            result.putString(AccountManager.KEY_PASSWORD, password);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    statusToken);
+            eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD, password);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+                    sessionBundle);
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, TestAuthenticatorActivity.class);
+            intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+            intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+            String errorMsg = "Default Error Message";
+            if (options != null) {
+                errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+                errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+            }
+            result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+            result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+        }
+
+        try {
+            return (isCallbackRequired) ? null : result;
+        } finally {
+            if (isCallbackRequired) {
+                response.onResult(result);
+            }
+        }
+    }
+
+    /**
+     * Prompts user to re-authenticate to a specific account but defers updating local credentials.
+     */
+    @Override
+    public Bundle startUpdateCredentialsSession(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+
+        if (!mAccountType.equals(account.type)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        String accountName = null;
+        boolean isCallbackRequired = false;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+            isCallbackRequired = options.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+            sessionBundle = options.getBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+        }
+
+        Bundle result = new Bundle();
+        String statusToken = Fixtures.PREFIX_STATUS_TOKEN + accountName;
+        String password = Fixtures.PREFIX_PASSWORD + accountName;
+        if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+            result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN, statusToken);
+            result.putString(AccountManager.KEY_PASSWORD, password);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    statusToken);
+            eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD, password);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+                    sessionBundle);
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, TestAuthenticatorActivity.class);
+            intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+            intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+            String errorMsg = "Default Error Message";
+            if (options != null) {
+                errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+                errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+            }
+            result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+            result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+        }
+
+        try {
+            return (isCallbackRequired) ? null : result;
+        } finally {
+            if (isCallbackRequired) {
+                response.onResult(result);
+            }
+        }
+    }
+
+}
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java b/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java
index f8636a0..b969caa 100644
--- a/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java
@@ -31,9 +31,12 @@
 
     public static final String TYPE_STANDARD_UNAFFILIATED =
             "android.accounts.test.standard.unaffiliated";
+    public static final String TYPE_CUSTOM_UNAFFILIATED =
+            "android.accounts.test.custom.unaffiliated";
 
     public static final String PREFIX_TOKEN = "token:";
     public static final String PREFIX_PASSWORD = "password:";
+    public static final String PREFIX_STATUS_TOKEN = "status_token:";
 
     public static final String SUFFIX_NAME_FIXTURE = "fixture.com";
     public static final String SUFFIX_NAME_TEST = "test.com";
@@ -52,6 +55,10 @@
             PREFIX_NAME_SUCCESS + "@" + SUFFIX_NAME_FIXTURE,
             TYPE_STANDARD_UNAFFILIATED);
 
+    public static final Account ACCOUNT_CUSTOM_UNAFFILIATED_FIXTURE_SUCCESS = new Account(
+            PREFIX_NAME_SUCCESS + "@" + SUFFIX_NAME_FIXTURE,
+            TYPE_CUSTOM_UNAFFILIATED);
+
     public static List<String> getFixtureAccountNames() {
         List<String> accountNames = new ArrayList<>(accountNamePrefixes.length);
         for (String prefix : accountNamePrefixes) {
@@ -70,5 +77,7 @@
     public static final String KEY_RESULT = "test:result";
     public static final String KEY_TOKEN_EXPIRY = "test:token_duration";
 
+    public static final String KEY_ACCOUNT_SESSION_BUNDLE = "test:account_session_bundle";
+
     private Fixtures() {}
 }
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.aidl b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.aidl
new file mode 100644
index 0000000..4819ebb
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.aidl
@@ -0,0 +1,3 @@
+package android.accounts.cts.common.tx;
+
+parcelable StartAddAccountSessionTx;
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.java b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.java
new file mode 100644
index 0000000..12a11ff
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.java
@@ -0,0 +1,65 @@
+package android.accounts.cts.common.tx;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StartAddAccountSessionTx implements Parcelable {
+
+    public static final Parcelable.Creator<StartAddAccountSessionTx> CREATOR = new Parcelable.Creator<StartAddAccountSessionTx>() {
+
+        @Override
+        public StartAddAccountSessionTx createFromParcel(Parcel in) {
+            return new StartAddAccountSessionTx(in);
+        }
+
+        @Override
+        public StartAddAccountSessionTx[] newArray(int size) {
+            return new StartAddAccountSessionTx[size];
+        }
+    };
+
+    public final String accountType;
+    public final String authTokenType;
+    public final List<String> requiredFeatures = new ArrayList<>();
+    public final Bundle options;
+    public final Bundle result;
+
+    private StartAddAccountSessionTx(Parcel in) {
+        accountType = in.readString();
+        authTokenType = in.readString();
+        in.readStringList(requiredFeatures);
+        options = in.readBundle();
+        result = in.readBundle();
+    }
+
+    public StartAddAccountSessionTx(String accountType, String authTokenType, String[] requiredFeatures,
+            Bundle options, Bundle result) {
+        this.accountType = accountType;
+        this.authTokenType = authTokenType;
+        if (requiredFeatures != null) {
+            for (String feature : requiredFeatures) {
+                this.requiredFeatures.add(feature);
+            }
+        }
+        this.options = options;
+        this.result = result;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(accountType);
+        out.writeString(authTokenType);
+        out.writeStringList(requiredFeatures);
+        out.writeBundle(options);
+        out.writeBundle(result);
+    }
+}
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountAuthenticatorDummyActivity.java b/tests/tests/accounts/src/android/accounts/cts/AccountAuthenticatorDummyActivity.java
new file mode 100644
index 0000000..76276b2
--- /dev/null
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountAuthenticatorDummyActivity.java
@@ -0,0 +1,26 @@
+package android.accounts.cts;
+
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.cts.common.Fixtures;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * TODO: Insert description here. (generated by sandrakwan)
+ */
+public class AccountAuthenticatorDummyActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Intent intent = getIntent();
+        AccountAuthenticatorResponse response = intent.getParcelableExtra(Fixtures.KEY_CALLBACK);
+        Intent result = intent.getParcelableExtra(Fixtures.KEY_RESULT);
+        if (response != null) {
+            response.onResult(result.getExtras());
+        }
+        setResult(RESULT_OK, result);
+        finish();
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
index 4350191..7d7906d 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
@@ -24,8 +24,10 @@
 import android.accounts.AuthenticatorException;
 import android.accounts.OnAccountsUpdateListener;
 import android.accounts.OperationCanceledException;
+import android.accounts.cts.common.Fixtures;
 import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -60,6 +62,8 @@
 
     public static final String ACCOUNT_PASSWORD = "android.accounts.cts.account.password";
 
+    public static final String ACCOUNT_STATUS_TOKEN = "android.accounts.cts.account.status.token";
+
     public static final String AUTH_TOKEN_TYPE = "mockAuthTokenType";
     public static final String AUTH_EXPIRING_TOKEN_TYPE = "mockAuthExpiringTokenType";
     public static final String AUTH_TOKEN_LABEL = "mockAuthTokenLabel";
@@ -94,6 +98,29 @@
     public static final Account CUSTOM_TOKEN_ACCOUNT =
             new Account(ACCOUNT_NAME,ACCOUNT_TYPE_CUSTOM);
 
+    public static final String SESSION_DATA_NAME_1 = "session.data.name.1";
+    public static final String SESSION_DATA_NAME_2 = "session.data.name.2";
+    public static final String SESSION_DATA_NAME_3 = "session.data.name.3";
+    public static final String SESSION_DATA_VALUE_1 = "session.data.value.1";
+    public static final int SESSION_DATA_VALUE_2 = 364;
+
+    public static Bundle getSessionBundle(String accountName) {
+        Bundle bundle = new Bundle();
+        bundle.putString(SESSION_DATA_NAME_1, SESSION_DATA_VALUE_1);
+        bundle.putInt(SESSION_DATA_NAME_2, SESSION_DATA_VALUE_2);
+        // Test null value in Bundle.
+        bundle.putParcelable(SESSION_DATA_NAME_3, null);
+        bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
+        bundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        bundle.putAll(OPTIONS_BUNDLE);
+        return bundle;
+    }
+
+    public static final String ERROR_MESSAGE = "android.accounts.cts.account.error.message";
+
+    public static final String KEY_CIPHER = "cipher";
+    public static final String KEY_MAC = "mac";
+
     private static MockAccountAuthenticator mockAuthenticator;
     private static final int LATCH_TIMEOUT_MS = 500;
     private static AccountManager am;
@@ -1967,4 +1994,2052 @@
         }
     }
 
+    /**
+     * Tests a basic startAddAccountSession() which returns a bundle containing
+     * encrypted session bundle, account password and status token.
+     */
+    public void testStartAddAccountSession()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        validateAccountAndAuthTokenType();
+        validateFeatures();
+
+        validateOptions(options, mockAuthenticator.mOptionsStartAddAccountSession);
+        assertNotNull(mockAuthenticator.mOptionsStartAddAccountSession);
+        assertEquals(accountName, mockAuthenticator.mOptionsStartAddAccountSession
+                .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        validateSystemOptions(mockAuthenticator.mOptionsStartAddAccountSession);
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startAddAccountSession() with null session bundle. Only account
+     * password and status token should be included in the result as session
+     * bundle is not inspected.
+     */
+    public void testStartAddAccountSessionWithNullSessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        validateAccountAndAuthTokenType();
+        validateFeatures();
+
+        validateOptions(options, mockAuthenticator.mOptionsStartAddAccountSession);
+        assertNotNull(mockAuthenticator.mOptionsStartAddAccountSession);
+        assertEquals(accountName, mockAuthenticator.mOptionsStartAddAccountSession
+                .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        validateSystemOptions(mockAuthenticator.mOptionsStartAddAccountSession);
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        assertNull(resultBundle.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+        assertEquals(ACCOUNT_PASSWORD, resultBundle.getString(AccountManager.KEY_PASSWORD));
+        assertEquals(ACCOUNT_STATUS_TOKEN,
+                resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    /**
+     * Tests startAddAccountSession() with empty session bundle. An encrypted
+     * session bundle, account password and status token should be included in
+     * the result as session bundle is not inspected.
+     */
+    public void testStartAddAccountSessionWithEmptySessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, new Bundle());
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        validateAccountAndAuthTokenType();
+        validateFeatures();
+
+        validateOptions(options, mockAuthenticator.mOptionsStartAddAccountSession);
+        assertNotNull(mockAuthenticator.mOptionsStartAddAccountSession);
+        assertEquals(accountName, mockAuthenticator.mOptionsStartAddAccountSession
+                .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        validateSystemOptions(mockAuthenticator.mOptionsStartAddAccountSession);
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startAddAccountSession with authenticator activity started. When
+     * Activity is provided, AccountManager would start the resolution Intent
+     * and return the final result which contains an encrypted session bundle,
+     * account password and status token.
+     */
+    public void testStartAddAccountSessionIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        validateAccountAndAuthTokenType();
+        validateFeatures();
+
+        validateStartAddAccountSessionOptions(accountName, options);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startAddAccountSession with KEY_INTENT returned but not started
+     * automatically. When no Activity is provided and authenticator requires
+     * additional data from user, KEY_INTENT will be returned by AccountManager.
+     */
+    public void testStartAddAccountSessionWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        validateAccountAndAuthTokenType();
+        validateFeatures();
+
+        validateStartAddAccountSessionOptions(accountName, options);
+
+        // Assert returned result
+        Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+        // Assert that KEY_INTENT is returned.
+        assertNotNull(returnIntent);
+        assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+        // Assert that no other data is returned.
+        assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+        assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+        assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+    }
+
+    /**
+     * Tests startAddAccountSession error case. AuthenticatorException is
+     * expected when authenticator return
+     * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+     */
+    public void testStartAddAccountSessionError() throws IOException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+        options.putAll(OPTIONS_BUNDLE);
+
+        try {
+            startAddAccountSession(
+                    am,
+                    ACCOUNT_TYPE,
+                    AUTH_TOKEN_TYPE,
+                    REQUIRED_FEATURES,
+                    options,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("startAddAccountSession should throw AuthenticatorException in error case.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    /**
+     * Tests startAddAccountSession() with callback and handler. An encrypted
+     * session bundle, account password and status token should be included in
+     * the result. Callback should be triggered with the result regardless of a
+     * handler is provider or not.
+     */
+    public void testStartAddAccountSessionWithCallbackAndHandler()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartAddAccountSessionWithCallbackAndHandler(null /* handler */);
+        testStartAddAccountSessionWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startAddAccountSession() with callback and handler and activity
+     * started. When Activity is provided, AccountManager would start the
+     * resolution Intent and return the final result which contains an encrypted
+     * session bundle, account password and status token. Callback should be
+     * triggered with the result regardless of a handler is provider or not.
+     */
+    public void testStartAddAccountSessionWithCallbackAndHandlerWithIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartAddAccountSessionWithCallbackAndHandlerWithIntervene(null /* handler */);
+        testStartAddAccountSessionWithCallbackAndHandlerWithIntervene(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startAddAccountSession() with callback and handler with KEY_INTENT
+     * returned. When no Activity is provided and authenticator requires
+     * additional data from user, KEY_INTENT will be returned by AccountManager
+     * in callback regardless of a handler is provider or not.
+     */
+    public void testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent(null /* handler */);
+        testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startAddAccountSession() error case with callback and handler.
+     * AuthenticatorException is expected when authenticator return
+     * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+     */
+    public void testStartAddAccountSessionErrorWithCallbackAndHandler()
+            throws IOException, OperationCanceledException {
+        testStartAddAccountSessionErrorWithCallbackAndHandler(null /* handler */);
+        testStartAddAccountSessionErrorWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+    }
+
+    private void testStartAddAccountSessionWithCallbackAndHandler(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final Bundle options = new Bundle();
+        final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = null;
+                try {
+                    resultBundle = bundleFuture.getResult();
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    fail("should not throw an AuthenticatorException");
+                }
+
+                // Assert parameters has been passed correctly
+                validateAccountAndAuthTokenType();
+                validateFeatures();
+
+                validateStartAddAccountSessionOptions(accountName, options);
+
+                // Assert returned result
+                // Assert that auth token was stripped.
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+                validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                callback,
+                handler);
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private void testStartAddAccountSessionWithCallbackAndHandlerWithIntervene(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final Bundle options = new Bundle();
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = null;
+                try {
+                    resultBundle = bundleFuture.getResult();
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    fail("should not throw an AuthenticatorException");
+                }
+
+                // Assert parameters has been passed correctly
+                validateAccountAndAuthTokenType();
+                validateFeatures();
+
+                validateStartAddAccountSessionOptions(accountName, options);
+
+                // Assert returned result
+                assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+                // Assert that auth token was stripped.
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+                validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                callback,
+                handler);
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private void testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final Bundle options = new Bundle();
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = null;
+                try {
+                    resultBundle = bundleFuture.getResult();
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    fail("should not throw an AuthenticatorException");
+                }
+
+                // Assert parameters has been passed correctly
+                validateAccountAndAuthTokenType();
+                validateFeatures();
+
+                validateStartAddAccountSessionOptions(accountName, options);
+
+                // Assert returned result
+                Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+                // Assert KEY_INTENT is returned.
+                assertNotNull(returnIntent);
+                assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+                // Assert that no other data is returned.
+                assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+                assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+                assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+
+                latch.countDown();
+            }
+        };
+
+        startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                callback,
+                handler);
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private void testStartAddAccountSessionErrorWithCallbackAndHandler(Handler handler)
+            throws IOException, OperationCanceledException {
+        final Bundle options = new Bundle();
+        final String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+        options.putAll(OPTIONS_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                try {
+                    bundleFuture.getResult();
+                    fail("should have thrown an AuthenticatorException");
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    latch.countDown();
+                }
+            }
+        };
+
+        try {
+            startAddAccountSession(
+                    am,
+                    ACCOUNT_TYPE,
+                    AUTH_TOKEN_TYPE,
+                    REQUIRED_FEATURES,
+                    options,
+                    mActivity,
+                    callback,
+                    handler);
+            // AuthenticatorException should be thrown when authenticator
+            // returns AccountManager.ERROR_CODE_INVALID_RESPONSE.
+            fail("should have thrown an AuthenticatorException");
+        } catch (AuthenticatorException e1) {
+        }
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private Bundle startAddAccountSession(AccountManager am, String accountType,
+            String authTokenType, String[] requiredFeatures, Bundle options, Activity activity,
+            AccountManagerCallback<Bundle> callback, Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+
+        AccountManagerFuture<Bundle> futureBundle = am.startAddAccountSession(
+                accountType,
+                authTokenType,
+                requiredFeatures,
+                options,
+                activity,
+                callback,
+                handler);
+
+        Bundle resultBundle = futureBundle.getResult();
+        assertTrue(futureBundle.isDone());
+        assertNotNull(resultBundle);
+
+        return resultBundle;
+    }
+
+    private void validateStartAddAccountSessionOptions(String accountName, Bundle options) {
+        validateOptions(options, mockAuthenticator.mOptionsStartAddAccountSession);
+        assertNotNull(mockAuthenticator.mOptionsStartAddAccountSession);
+        assertEquals(accountName, mockAuthenticator.mOptionsStartAddAccountSession
+                .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        validateSystemOptions(mockAuthenticator.mOptionsStartAddAccountSession);
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+        validateOptions(null, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        validateOptions(null, mockAuthenticator.mOptionsFinishSession);
+    }
+
+    private void validateSessionBundleAndPasswordAndStatusTokenResult(Bundle resultBundle) {
+        Bundle sessionBundle = resultBundle.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(sessionBundle);
+        // Assert that session bundle is encrypted and hence data not visible.
+        assertNull(sessionBundle.getString(SESSION_DATA_NAME_1));
+        assertEquals(ACCOUNT_PASSWORD, resultBundle.getString(AccountManager.KEY_PASSWORD));
+        assertEquals(ACCOUNT_STATUS_TOKEN,
+                resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    /**
+     * Test a basic startUpdateCredentialsSession() which returns a bundle containing
+     * encrypted session bundle, account password and status token.
+     */
+    public void testStartUpdateCredentialsSession()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                null /* authTokenType */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertNull(mockAuthenticator.getAuthTokenType());
+        assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+        validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() with null session bundle. Only account
+     * password and status token should be included in the result as session
+     * bundle is not inspected.
+     */
+    public void testStartUpdateCredentialsSessionWithNullSessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+        assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+        validateOptions(options, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        assertNotNull(mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        assertEquals(accountName, mockAuthenticator.mOptionsStartUpdateCredentialsSession
+                .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        assertNull(resultBundle.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+        assertEquals(ACCOUNT_PASSWORD, resultBundle.getString(AccountManager.KEY_PASSWORD));
+        assertEquals(ACCOUNT_STATUS_TOKEN,
+                resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() with empty session bundle. An encrypted
+     * session bundle, account password and status token should be included in
+     * the result as session bundle is not inspected.
+     */
+    public void testStartUpdateCredentialsSessionWithEmptySessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, new Bundle());
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+        assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+        validateOptions(options, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        assertNotNull(mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        assertEquals(accountName, mockAuthenticator.mOptionsStartUpdateCredentialsSession
+                .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession with authenticator activity started. When
+     * Activity is provided, AccountManager would start the resolution Intent
+     * and return the final result which contains an encrypted session bundle,
+     * account password and status token.
+     */
+    public void testStartUpdateCredentialsSessionIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+        assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+        validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession with KEY_INTENT returned but not
+     * started automatically. When no Activity is provided and authenticator requires
+     * additional data from user, KEY_INTENT will be returned by AccountManager.
+     */
+    public void testStartUpdateCredentialsSessionWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+        assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+        validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+        // Assert returned result
+        Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+        // Assert that KEY_INTENT is returned.
+        assertNotNull(returnIntent);
+        assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+        // Assert that no other data is returned.
+        assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+        assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+        assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession error case. AuthenticatorException is
+     * expected when authenticator return
+     * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+     */
+    public void testStartUpdateCredentialsSessionError()
+            throws IOException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+        options.putAll(OPTIONS_BUNDLE);
+
+        try {
+            startUpdateCredentialsSession(
+                    am,
+                    ACCOUNT,
+                    AUTH_TOKEN_TYPE,
+                    options,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("startUpdateCredentialsSession should throw AuthenticatorException in error.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() with callback and handler. An encrypted
+     * session bundle, account password and status token should be included in
+     * the result. Callback should be triggered with the result regardless of a
+     * handler is provider or not.
+     */
+    public void testStartUpdateCredentialsSessionWithCallbackAndHandler()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartUpdateCredentialsSessionWithCallbackAndHandler(null /* handler */);
+        testStartUpdateCredentialsSessionWithCallbackAndHandler(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() with callback and handler and
+     * activity started. When Activity is provided, AccountManager would start the
+     * resolution Intent and return the final result which contains an encrypted
+     * session bundle, account password and status token. Callback should be
+     * triggered with the result regardless of a handler is provider or not.
+     */
+    public void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene(null /* handler */);
+        testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() with callback and handler with
+     * KEY_INTENT returned. When no Activity is provided and authenticator requires
+     * additional data from user, KEY_INTENT will be returned by AccountManager
+     * in callback regardless of a handler is provider or not.
+     */
+    public void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent(null /* handler */);
+        testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() error case with callback and
+     * handler. AuthenticatorException is expected when authenticator return
+     * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+     */
+    public void testStartUpdateCredentialsSessionErrorWithCallbackAndHandler()
+            throws IOException, OperationCanceledException {
+        testStartUpdateCredentialsSessionErrorWithCallbackAndHandler(null /* handler */);
+        testStartUpdateCredentialsSessionErrorWithCallbackAndHandler(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    private void testStartUpdateCredentialsSessionWithCallbackAndHandler(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final Bundle options = new Bundle();
+        final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = null;
+                try {
+                    resultBundle = bundleFuture.getResult();
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    fail("should not throw an AuthenticatorException");
+                }
+
+                // Assert parameters has been passed correctly
+                assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+                assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+                validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+                // Assert returned result
+                // Assert that auth token was stripped.
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+                validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                mActivity,
+                callback,
+                handler);
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene(
+            Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+        final Bundle options = new Bundle();
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = null;
+                try {
+                    resultBundle = bundleFuture.getResult();
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    fail("should not throw an AuthenticatorException");
+                }
+
+                // Assert parameters has been passed correctly
+                assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+                assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+                validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+                // Assert returned result
+                assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+                // Assert that auth token was stripped.
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+                validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                mActivity,
+                callback,
+                handler);
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent(
+            Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+        final Bundle options = new Bundle();
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putAll(OPTIONS_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = null;
+                try {
+                    resultBundle = bundleFuture.getResult();
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    fail("should not throw an AuthenticatorException");
+                }
+
+                // Assert parameters has been passed correctly
+                assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+                assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+                validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+                // Assert returned result
+                Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+                // Assert KEY_INTENT is returned.
+                assertNotNull(returnIntent);
+                assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+                // Assert that no other data is returned.
+                assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+                assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+                assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+
+                latch.countDown();
+            }
+        };
+
+        startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null,
+                callback,
+                handler);
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private void testStartUpdateCredentialsSessionErrorWithCallbackAndHandler(Handler handler)
+            throws IOException, OperationCanceledException {
+        final Bundle options = new Bundle();
+        final String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+        options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+        options.putAll(OPTIONS_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                try {
+                    bundleFuture.getResult();
+                    fail("should have thrown an AuthenticatorException");
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    latch.countDown();
+                }
+            }
+        };
+
+        try {
+            startUpdateCredentialsSession(
+                    am,
+                    ACCOUNT,
+                    AUTH_TOKEN_TYPE,
+                    options,
+                    mActivity,
+                    callback,
+                    handler);
+            // AuthenticatorException should be thrown when authenticator
+            // returns AccountManager.ERROR_CODE_INVALID_RESPONSE.
+            fail("should have thrown an AuthenticatorException");
+        } catch (AuthenticatorException e1) {
+        }
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private Bundle startUpdateCredentialsSession(AccountManager am, Account account,
+            String authTokenType, Bundle options, Activity activity,
+            AccountManagerCallback<Bundle> callback, Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+
+        AccountManagerFuture<Bundle> futureBundle = am.startUpdateCredentialsSession(account,
+                authTokenType, options, activity, callback, handler);
+
+        Bundle resultBundle = futureBundle.getResult();
+        assertTrue(futureBundle.isDone());
+        assertNotNull(resultBundle);
+
+        return resultBundle;
+    }
+
+    private void validateStartUpdateCredentialsSessionOptions(String accountName, Bundle options) {
+        validateOptions(options, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        assertNotNull(mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        assertEquals(accountName, mockAuthenticator.mOptionsStartUpdateCredentialsSession
+                .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+        validateOptions(null, mockAuthenticator.mOptionsStartAddAccountSession);
+    }
+
+    /**
+     * Tests a basic finishSession() with session bundle created by
+     * startAddAccountSession(...). A bundle containing account name and account
+     * type is expected.
+     */
+    public void testFinishSessionWithStartAddAccountSession()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle sessionBundle = getSessionBundle(accountName);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+        validateFinishSessionOptions(accountName, sessionBundle);
+
+        // Assert returned result containing account name, type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests a basic finishSession() with session bundle created by
+     * startUpdateCredentialsSession(...). A bundle containing account name and account
+     * type is expected.
+     */
+    public void testFinishSessionWithStartUpdateCredentialsSession()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle sessionBundle = getSessionBundle(accountName);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startUpdateCredentialsSession(...)
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+        validateFinishSessionOptions(accountName, sessionBundle);
+
+        // Assert returned result containing account name, type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests finishSession() with null session bundle. IllegalArgumentException
+     * is expected as session bundle cannot be null.
+     */
+    public void testFinishSessionWithNullSessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        try {
+            finishSession(
+                    am,
+                    null /* sessionBundle */,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown IllegalArgumentException when sessionBundle is null");
+        } catch (IllegalArgumentException e) {
+
+        }
+    }
+
+    /**
+     * Tests finishSession() with empty session bundle. IllegalArgumentException
+     * is expected as session bundle would always contain something if it was
+     * processed properly by AccountManagerService.
+     */
+    public void testFinishSessionWithEmptySessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+
+        try {
+            finishSession(am,
+                    new Bundle(),
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown IllegalArgumentException when sessionBundle is empty");
+        } catch (IllegalArgumentException e) {
+
+        }
+    }
+
+    /**
+     * Tests finishSession() with sessionBundle not encrypted by the right key.
+     * AuthenticatorException is expected if AccountManagerService failed to
+     * decrypt the session bundle because of wrong key or crypto data was
+     * tampered.
+     */
+    public void testFinishSessionWithDecryptionError()
+            throws IOException, OperationCanceledException {
+        byte[] mac = new byte[] {
+                1, 1, 0, 0
+        };
+        byte[] cipher = new byte[] {
+                1, 0, 0, 1, 1
+        };
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putByteArray(KEY_MAC, mac);
+        sessionBundle.putByteArray(KEY_CIPHER, cipher);
+
+        try {
+            finishSession(am,
+                    sessionBundle,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown AuthenticatorException when failed to decrypt sessionBundle");
+        } catch (AuthenticatorException e) {
+
+        }
+    }
+
+    /**
+     * Tests finishSession() with sessionBundle invalid contents.
+     * AuthenticatorException is expected if AccountManagerService failed to
+     * decrypt the session bundle because of wrong key or crypto data was
+     * tampered.
+     */
+    public void testFinishSessionWithInvalidEncryptedContent()
+            throws IOException, OperationCanceledException {
+        byte[] mac = new byte[] {};
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putByteArray(KEY_MAC, mac);
+
+        try {
+            finishSession(am,
+                    sessionBundle,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown AuthenticatorException when failed to decrypt sessionBundle");
+        } catch (AuthenticatorException e) {
+
+        }
+    }
+
+    /**
+     * Tests a finishSession() when account type is not added to session bundle
+     * by startAddAccount(...) of authenticator. A bundle containing account
+     * name and account type should still be returned as AccountManagerSerivce
+     * will always add account type to the session bundle before encrypting it.
+     */
+    public void testFinishSessionFromStartAddAccountWithoutAccountType()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+
+        // Create a session bundle without account type for MockAccountAuthenticator to return
+        Bundle sessionBundle = getSessionBundle(accountName);
+        sessionBundle.remove(AccountManager.KEY_ACCOUNT_TYPE);
+
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, sessionBundle);
+
+        // Assert returned result containing account name, type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests a finishSession() when account type is not added to session bundle
+     * by startUpdateCredentialsSession(...) of authenticator. A bundle
+     * containing account name and account type should still be returned as
+     * AccountManagerSerivce will always add account type to the session bundle
+     * before encrypting it.
+     */
+    public void testFinishSessionFromStartUpdateCredentialsSessionWithoutAccountType()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+
+        // Create a session bundle without account type for MockAccountAuthenticator to return
+        Bundle sessionBundle = getSessionBundle(accountName);
+        sessionBundle.remove(AccountManager.KEY_ACCOUNT_TYPE);
+
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, sessionBundle);
+
+        // Assert returned result containing account name, type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests a finishSession() when a different account type is added to session bundle
+     * by startAddAccount(...) of authenticator. A bundle containing account
+     * name and the correct account type should be returned as AccountManagerSerivce
+     * will always overrides account type to the session bundle before encrypting it.
+     */
+    public void testFinishSessionFromStartAddAccountAccountTypeOverriden()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+
+        // Create a session bundle with a different account type for
+        // MockAccountAuthenticator to return
+        Bundle sessionBundle = getSessionBundle(accountName);
+        sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, "randomAccountType");
+
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, sessionBundle);
+
+        // Assert returned result containing account name, correct type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests a finishSession() when a different account type is added to session bundle
+     * by startUpdateCredentialsSession(...) of authenticator. A bundle
+     * containing account name and the correct account type should be returned as
+     * AccountManagerSerivce will always override account type to the session bundle
+     * before encrypting it.
+     */
+    public void testFinishSessionFromStartUpdateCredentialsSessionAccountTypeOverriden()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+
+        // Create a session bundle with a different account type for
+        // MockAccountAuthenticator to return
+        Bundle sessionBundle = getSessionBundle(accountName);
+        sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, "randomAccountType");
+
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, sessionBundle);
+
+        // Assert returned result containing account name, correct type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests finishSession with authenticator activity started. When additional
+     * info is needed from user for finishing the session and an Activity was
+     * provided by caller, the resolution intent will be started automatically.
+     * A bundle containing account name and type will be returned.
+     */
+    public void testFinishSessionIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle sessionBundle = getSessionBundle(accountName);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, sessionBundle);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert returned result containing account name, type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests finishSession with KEY_INTENT returned but not started
+     * automatically. When additional info is needed from user for finishing the
+     * session and no Activity was provided by caller, the resolution intent
+     * will not be started automatically. A bundle containing KEY_INTENT will be
+     * returned instead.
+     */
+    public void testFinishSessionWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle sessionBundle = getSessionBundle(accountName);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        resultBundle = finishSession(am, encryptedSessionBundle, null /* activity */,
+                null /* callback */, null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, sessionBundle);
+
+        // Assert returned result
+        Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+        assertNotNull(returnIntent);
+        assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+
+        assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_NAME));
+        assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_TYPE));
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+    }
+
+    /**
+     * Tests finishSession error case. AuthenticatorException is expected when
+     * AccountManager.ERROR_CODE_INVALID_RESPONSE is returned by authenticator.
+     */
+    public void testFinishSessionError()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle sessionBundle = new Bundle();
+        String accountNameForFinish = Fixtures.PREFIX_NAME_ERROR + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountNameForFinish);
+        sessionBundle.putInt(AccountManager.KEY_ERROR_CODE,
+                AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        sessionBundle.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+
+        try {
+            finishSession(
+                    am,
+                    encryptedSessionBundle,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("finishSession should throw AuthenticatorException in error case.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    /**
+     * Tests finishSession() with callback and handler. A bundle containing
+     * account name and type should be returned via the callback regardless of
+     * whether a handler is provided.
+     */
+    public void testFinishSessionWithCallbackAndHandler()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+
+        testFinishSessionWithCallbackAndHandler(null /* handler */);
+        testFinishSessionWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests finishSession() with callback and handler and activity started.
+     * When additional info is needed from user for finishing the session and an
+     * Activity was provided by caller, the resolution intent will be started
+     * automatically. A bundle containing account name and type will be returned
+     * via the callback regardless of if handler is provided or now.
+     */
+    public void testFinishSessionWithCallbackAndHandlerWithIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+
+        testFinishSessionWithCallbackAndHandlerWithIntervene(null /* handler */);
+        testFinishSessionWithCallbackAndHandlerWithIntervene(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests finishSession() with callback and handler with KEY_INTENT
+     * returned. When additional info is needed from user for finishing the
+     * session and no Activity was provided by caller, the resolution intent
+     * will not be started automatically. A bundle containing KEY_INTENT will be
+     * returned instead via callback regardless of if handler is provided or not.
+     */
+    public void testFinishSessionWithCallbackAndHandlerWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+
+        testFinishSessionWithCallbackAndHandlerWithReturnIntent(null /* handler */);
+        testFinishSessionWithCallbackAndHandlerWithReturnIntent(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests finishSession() error case with callback and handler.
+     * AuthenticatorException is expected when
+     * AccountManager.ERROR_CODE_INVALID_RESPONSE is returned by authenticator.
+     */
+    public void testFinishSessionErrorWithCallbackAndHandler()
+            throws IOException, OperationCanceledException, AuthenticatorException {
+
+        testFinishSessionErrorWithCallbackAndHandler(null /* handler */);
+        testFinishSessionErrorWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+    }
+
+    private void testFinishSessionWithCallbackAndHandler(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle sessionBundle = getSessionBundle(accountName);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = null;
+                try {
+                    resultBundle = bundleFuture.getResult();
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    fail("should not throw an AuthenticatorException");
+                }
+
+                // Assert parameters has been passed correctly
+                assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+                validateFinishSessionOptions(accountName, sessionBundle);
+
+                // Assert returned result containing account name, type but not auth token type.
+                validateAccountAndNoAuthTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        finishSession(am, encryptedSessionBundle, mActivity, callback, handler);
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private void testFinishSessionWithCallbackAndHandlerWithIntervene(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle sessionBundle = getSessionBundle(accountName);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = null;
+                try {
+                    resultBundle = bundleFuture.getResult();
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    fail("should not throw an AuthenticatorException");
+                }
+
+                // Assert parameters has been passed correctly
+                assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+                validateFinishSessionOptions(accountName, sessionBundle);
+
+                // Assert returned result
+                assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+                // Assert returned result containing account name, type but not auth token type.
+                validateAccountAndNoAuthTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        finishSession(am, encryptedSessionBundle, mActivity, callback, handler);
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private void testFinishSessionWithCallbackAndHandlerWithReturnIntent(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle sessionBundle = getSessionBundle(accountName);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = null;
+                try {
+                    resultBundle = bundleFuture.getResult();
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    fail("should not throw an AuthenticatorException");
+                }
+
+                // Assert parameters has been passed correctly
+                assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+                validateFinishSessionOptions(accountName, sessionBundle);
+
+                // Assert returned result
+                Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+                assertNotNull(returnIntent);
+                assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+
+                assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_NAME));
+                assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_TYPE));
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+
+                latch.countDown();
+            }
+        };
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+        finishSession(am, encryptedSessionBundle, null, callback, handler);
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private void testFinishSessionErrorWithCallbackAndHandler(Handler handler)
+            throws IOException, OperationCanceledException, AuthenticatorException {
+        Bundle sessionBundle = new Bundle();
+        String accountNameForFinish = Fixtures.PREFIX_NAME_ERROR + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountNameForFinish);
+        sessionBundle.putInt(AccountManager.KEY_ERROR_CODE,
+                AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        sessionBundle.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                try {
+                    bundleFuture.getResult();
+                    fail("should have thrown an AuthenticatorException");
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    latch.countDown();
+                }
+            }
+        };
+
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+
+        try {
+            finishSession(am, encryptedSessionBundle, mActivity, callback, handler);
+            fail("should have thrown an AuthenticatorException");
+        } catch (AuthenticatorException e1) {
+        }
+
+        // Wait with timeout for the callback to do its work
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private Bundle finishSession(AccountManager am, Bundle sessionBundle, Activity activity,
+            AccountManagerCallback<Bundle> callback, Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+
+        AccountManagerFuture<Bundle> futureBundle = am.finishSession(
+                sessionBundle,
+                activity,
+                callback,
+                handler);
+
+        Bundle resultBundle = futureBundle.getResult();
+        assertTrue(futureBundle.isDone());
+        assertNotNull(resultBundle);
+
+        return resultBundle;
+    }
+
+    private void validateFinishSessionOptions(String accountName, Bundle options) {
+        validateOptions(options, mockAuthenticator.mOptionsFinishSession);
+        assertNotNull(mockAuthenticator.mOptionsFinishSession);
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.mOptionsFinishSession
+                .getString(AccountManager.KEY_ACCOUNT_TYPE));
+        assertEquals(accountName,
+                mockAuthenticator.mOptionsFinishSession.getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        validateSystemOptions(mockAuthenticator.mOptionsFinishSession);
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+        validateOptions(null, mockAuthenticator.mOptionsStartAddAccountSession);
+        validateOptions(null, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+    }
 }
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
index 2068f4c..0105782 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
@@ -23,8 +23,11 @@
 import android.accounts.OperationCanceledException;
 import android.accounts.cts.common.AuthenticatorContentProvider;
 import android.accounts.cts.common.Fixtures;
+import android.accounts.cts.common.tx.AddAccountTx;
+import android.accounts.cts.common.tx.UpdateCredentialsTx;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.test.AndroidTestCase;
 
@@ -222,5 +225,226 @@
                 getContext().getPackageName());
         assertEquals(0, accounts.length);
     }
+
+    /**
+     * Tests startAddAccountSession default implementation. An encrypted session
+     * bundle should always be returned without password or status token.
+     */
+    public void testStartAddAccountSessionDefaultImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+        AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession(
+                Fixtures.TYPE_STANDARD_UNAFFILIATED,
+                null /* authTokenType */,
+                null /* requiredFeatures */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Validate that auth token was stripped from result.
+        assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+
+        // Validate that no password nor status token is returned in the result
+        // for default implementation.
+        validateNullPasswordAndStatusToken(result);
+
+        Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        // Validate session bundle is returned but data in the bundle is
+        // encrypted and hence not visible.
+        assertNotNull(sessionBundle);
+        assertNull(sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE));
+    }
+
+    private void validateNullPasswordAndStatusToken(Bundle result) {
+        assertNull(result.getString(AccountManager.KEY_PASSWORD));
+        assertNull(result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession default implementation. An encrypted session
+     * bundle should always be returned without password or status token.
+     */
+    public void testStartUpdateCredentialsSessionDefaultImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+        AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession(
+                Fixtures.ACCOUNT_UNAFFILIATED_FIXTURE_SUCCESS,
+                null /* authTokenType */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Validate no auth token in result.
+        assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+
+        // Validate that no password nor status token is returned in the result
+        // for default implementation.
+        validateNullPasswordAndStatusToken(result);
+
+        Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        // Validate session bundle is returned but data in the bundle is
+        // encrypted and hence not visible.
+        assertNotNull(sessionBundle);
+        assertNull(sessionBundle.getString(Fixtures.KEY_ACCOUNT_NAME));
+    }
+
+    /**
+     * Tests finishSession default implementation with default startAddAccountSession.
+     * Only account name and account type should be returned as a bundle.
+     */
+    public void testFinishSessionAndStartAddAccountSessionDefaultImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException,
+            RemoteException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+        // First obtain an encrypted session bundle from startAddAccountSession(...) default
+        // implementation.
+        AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession(
+                Fixtures.TYPE_STANDARD_UNAFFILIATED,
+                null /* authTokenType */,
+                null /* requiredFeatures */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Assert that result contains a non-null session bundle.
+        Bundle escrowBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(escrowBundle);
+
+        // Now call finishSession(...) with the session bundle we just obtained.
+        future = mAccountManager.finishSession(
+                escrowBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Validate that parameters are passed to addAccount(...) correctly in default finishSession
+        // implementation.
+        Bundle providerBundle = mProviderClient.call(
+                AuthenticatorContentProvider.METHOD_GET,
+                null /* arg */,
+                null /* extras */);
+        providerBundle.setClassLoader(AddAccountTx.class.getClassLoader());
+        AddAccountTx addAccountTx = providerBundle
+                .getParcelable(AuthenticatorContentProvider.KEY_TX);
+        assertNotNull(addAccountTx);
+
+        // Assert parameters has been passed to addAccount(...) correctly
+        assertEquals(Fixtures.TYPE_STANDARD_UNAFFILIATED, addAccountTx.accountType);
+        assertNull(addAccountTx.authTokenType);
+
+        validateSystemOptions(addAccountTx.options);
+        // Validate options
+        assertNotNull(addAccountTx.options);
+        assertEquals(accountName, addAccountTx.options.getString(Fixtures.KEY_ACCOUNT_NAME));
+        // Validate features.
+        assertEquals(0, addAccountTx.requiredFeatures.size());
+
+        // Assert returned result contains correct account name, account type and null auth token.
+        assertEquals(accountName, result.get(AccountManager.KEY_ACCOUNT_NAME));
+        assertEquals(Fixtures.TYPE_STANDARD_UNAFFILIATED,
+                result.get(AccountManager.KEY_ACCOUNT_TYPE));
+        assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+    }
+
+    /**
+     * Tests finishSession default implementation with default startAddAccountSession.
+     * Only account name and account type should be returned as a bundle.
+     */
+    public void testFinishSessionAndStartUpdateCredentialsSessionDefaultImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException,
+            RemoteException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+        // First obtain an encrypted session bundle from startUpdateCredentialsSession(...) default
+        // implementation.
+        AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession(
+                Fixtures.ACCOUNT_UNAFFILIATED_FIXTURE_SUCCESS,
+                null /* authTokenTYpe */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Assert that result contains a non-null session bundle.
+        Bundle escrowBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(escrowBundle);
+
+        // Now call finishSession(...) with the session bundle we just obtained.
+        future = mAccountManager.finishSession(
+                escrowBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Validate that parameters are passed to updateCredentials(...) correctly in default
+        // finishSession implementation.
+        Bundle providerBundle = mProviderClient.call(
+                AuthenticatorContentProvider.METHOD_GET,
+                null /* arg */,
+                null /* extras */);
+        providerBundle.setClassLoader(UpdateCredentialsTx.class.getClassLoader());
+        UpdateCredentialsTx updateCredentialsTx = providerBundle
+                .getParcelable(AuthenticatorContentProvider.KEY_TX);
+        assertNotNull(updateCredentialsTx);
+
+        // Assert parameters has been passed to updateCredentials(...) correctly
+        assertEquals(Fixtures.ACCOUNT_UNAFFILIATED_FIXTURE_SUCCESS, updateCredentialsTx.account);
+        assertNull(updateCredentialsTx.authTokenType);
+
+        validateSystemOptions(updateCredentialsTx.options);
+        // Validate options
+        assertNotNull(updateCredentialsTx.options);
+        assertEquals(accountName, updateCredentialsTx.options.getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        // Assert returned result contains correct account name, account type and null auth token.
+        assertEquals(accountName, result.get(AccountManager.KEY_ACCOUNT_NAME));
+        assertEquals(Fixtures.TYPE_STANDARD_UNAFFILIATED,
+                result.get(AccountManager.KEY_ACCOUNT_TYPE));
+        assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+    }
+
+    private void validateSystemOptions(Bundle options) {
+        assertNotNull(options.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME));
+        assertTrue(options.containsKey(AccountManager.KEY_CALLER_UID));
+        assertTrue(options.containsKey(AccountManager.KEY_CALLER_PID));
+    }
 }
 
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffliatedCustomAuthenticatorTests.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffliatedCustomAuthenticatorTests.java
new file mode 100644
index 0000000..1329eb3
--- /dev/null
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffliatedCustomAuthenticatorTests.java
@@ -0,0 +1,139 @@
+
+package android.accounts.cts;
+
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.accounts.cts.common.Fixtures;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.test.AndroidTestCase;
+
+import java.io.IOException;
+
+/**
+ * Tests for AccountManager and AbstractAccountAuthenticator related behavior
+ * using {@link android.accounts.cts.common.CustomTestAccountAuthenticator}
+ * instances signed with different keys than the caller. This is important to
+ * test that portion of the default implementation of the
+ * {@link AccountManager#finishSession} API when implementers of
+ * {@link android.accounts.AbstractAccountAuthenticator} override only
+ * {@link AccountManager#startAddAccountSession} and/or
+ * {@link AccountManager#startUpdateCredentialsSession} but not
+ * {@link AccountManager#finishSession}.
+ * <p>
+ * You can run those unit tests with the following command line:
+ * <p>
+ * adb shell am instrument -e debug false -w -e class
+ * android.accounts.cts.AccountManagerUnaffiliatedCustomAuthenticatorTests
+ * android.accounts.cts/android.support.test.runner.AndroidJUnitRunner
+ */
+public class AccountManagerUnaffliatedCustomAuthenticatorTests extends AndroidTestCase {
+
+    private AccountManager mAccountManager;
+
+    @Override
+    public void setUp() throws Exception {
+        // bind to the diagnostic service and set it up.
+        mAccountManager = AccountManager.get(getContext());
+    }
+
+    /**
+     * Tests finishSession default implementation with custom
+     * startAddAccountSession implementation. AuthenticatorException is expected
+     * because default implementation cannot understand custom session bundle.
+     */
+    public void testFinishSessiontWithCustomStartAddAccountSessionImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        // Creates session bundle to be returned by custom implementation of
+        // startAddAccountSession of authenticator.
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, Fixtures.TYPE_CUSTOM_UNAFFILIATED);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+
+        // First get an encrypted session bundle from custom startAddAccountSession implementation.
+        AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession(
+                Fixtures.TYPE_CUSTOM_UNAFFILIATED,
+                null /* authTokenType */,
+                null /* requiredFeatures */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        Bundle decryptedBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(decryptedBundle);
+
+        try {
+            // Call default implementation of finishSession of authenticator
+            // with encrypted session bundle.
+            future = mAccountManager.finishSession(
+                    decryptedBundle,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            future.getResult();
+
+            fail("Should have thrown AuthenticatorException if finishSession is not overridden.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    /**
+     * Tests finishSession default implementation with custom
+     * startUpdateCredentialsSession implementation. AuthenticatorException is expected
+     * because default implementation cannot understand custom session bundle.
+     */
+    public void testFinishSessionWithCustomStartUpdateCredentialsSessionImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        // Creates session bundle to be returned by custom implementation of
+        // startUpdateCredentialsSession of authenticator.
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, Fixtures.TYPE_CUSTOM_UNAFFILIATED);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+
+        // First get an encrypted session bundle from custom
+        // startUpdateCredentialsSession implementation.
+        AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession(
+                Fixtures.ACCOUNT_CUSTOM_UNAFFILIATED_FIXTURE_SUCCESS,
+                null /* authTokenType */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        Bundle decryptedBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(decryptedBundle);
+
+        try {
+            // Call default implementation of finishSession of authenticator
+            // with encrypted session bundle.
+            future = mAccountManager.finishSession(
+                    decryptedBundle,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            future.getResult();
+
+            fail("Should have thrown AuthenticatorException if finishSession is not overridden.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+}
diff --git a/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java b/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
index c1b08de..6f355fb 100644
--- a/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
+++ b/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
@@ -21,6 +21,7 @@
 import android.accounts.AccountAuthenticatorResponse;
 import android.accounts.AccountManager;
 import android.accounts.NetworkErrorException;
+import android.accounts.cts.common.Fixtures;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
@@ -55,6 +56,9 @@
     public Bundle mOptionsConfirmCredentials;
     public Bundle mOptionsAddAccount;
     public Bundle mOptionsGetAuthToken;
+    public Bundle mOptionsStartAddAccountSession;
+    public Bundle mOptionsStartUpdateCredentialsSession;
+    public Bundle mOptionsFinishSession;
     Account mAccount;
     String[] mFeatures;
 
@@ -115,6 +119,9 @@
         mOptionsAddAccount = null;
         mOptionsGetAuthToken = null;
         mOptionsConfirmCredentials = null;
+        mOptionsStartAddAccountSession = null;
+        mOptionsStartUpdateCredentialsSession = null;
+        mOptionsFinishSession = null;
         mAccount = null;
         mFeatures = null;
     }
@@ -295,4 +302,210 @@
         }
         return result;
     }
+
+    /**
+     * Starts add account flow of the specified accountType to authenticate
+     * user.
+     */
+    @Override
+    public Bundle startAddAccountSession(AccountAuthenticatorResponse response, String accountType,
+            String authTokenType, String[] requiredFeatures, Bundle options)
+            throws NetworkErrorException {
+
+        this.mResponse = response;
+        this.mAccountType = accountType;
+        this.mAuthTokenType = authTokenType;
+        this.mRequiredFeatures = requiredFeatures;
+        this.mOptionsStartAddAccountSession = options;
+
+        String accountName = null;
+        boolean isCallbackRequired = false;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+            isCallbackRequired = options.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+            sessionBundle = options.getBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+            result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerTest.ACCOUNT_STATUS_TOKEN);
+            result.putString(AccountManager.KEY_PASSWORD, AccountManagerTest.ACCOUNT_PASSWORD);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerTest.ACCOUNT_STATUS_TOKEN);
+            eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD,
+                    AccountManagerTest.ACCOUNT_PASSWORD);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+                    sessionBundle);
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+            intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+            intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+            String errorMsg = "Default Error Message";
+            if (options != null) {
+                errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+                errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+            }
+            result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+            result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+        }
+
+        try {
+            return (isCallbackRequired) ? null : result;
+        } finally {
+            if (isCallbackRequired) {
+                response.onResult(result);
+            }
+        }
+
+    }
+
+    /**
+     * Starts the update credentials flow to re-auth user but does not update
+     * locally stored credentials for an account.
+     */
+    @Override
+    public Bundle startUpdateCredentialsSession(AccountAuthenticatorResponse response, Account account,
+            String authTokenType, Bundle options) throws NetworkErrorException {
+
+        mResponse = response;
+        mAccount = account;
+        mAuthTokenType = authTokenType;
+        mOptionsStartUpdateCredentialsSession = options;
+
+        String accountName = null;
+        boolean isCallbackRequired = false;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+            isCallbackRequired = options.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+            sessionBundle = options.getBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+            result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerTest.ACCOUNT_STATUS_TOKEN);
+            result.putString(AccountManager.KEY_PASSWORD, AccountManagerTest.ACCOUNT_PASSWORD);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerTest.ACCOUNT_STATUS_TOKEN);
+            eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD,
+                    AccountManagerTest.ACCOUNT_PASSWORD);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+                    sessionBundle);
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+            intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+            intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+            String errorMsg = "Default Error Message";
+            if (options != null) {
+                errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+                errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+            }
+            result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+            result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+        }
+
+        try {
+            return (isCallbackRequired) ? null : result;
+        } finally {
+            if (isCallbackRequired) {
+                response.onResult(result);
+            }
+        }
+    }
+
+    /**
+     * Finishes account session started by adding the account to device or updating the local
+     * credentials.
+     */
+    @Override
+    public Bundle finishSession(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            Bundle sessionBundle) throws NetworkErrorException {
+
+        this.mResponse = response;
+        this.mAccountType = accountType;
+        this.mOptionsFinishSession = sessionBundle;
+
+        String accountName = null;
+        boolean isCallbackRequired = false;
+        if (sessionBundle != null) {
+            accountName = sessionBundle.getString(Fixtures.KEY_ACCOUNT_NAME);
+            isCallbackRequired = sessionBundle.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putString(AccountManager.KEY_ACCOUNT_NAME, AccountManagerTest.ACCOUNT_NAME);
+            result.putString(AccountManager.KEY_ACCOUNT_TYPE, AccountManagerTest.ACCOUNT_TYPE);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME,
+                    AccountManagerTest.ACCOUNT_NAME);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE,
+                    AccountManagerTest.ACCOUNT_TYPE);
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+            intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+            intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+            String errorMsg = "Default Error Message";
+            if (sessionBundle != null) {
+                errorCode = sessionBundle.getInt(AccountManager.KEY_ERROR_CODE);
+                errorMsg = sessionBundle.getString(AccountManager.KEY_ERROR_MESSAGE);
+            }
+            result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+            result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+        }
+
+        try {
+            return (isCallbackRequired) ? null : result;
+        } finally {
+            if (isCallbackRequired) {
+                response.onResult(result);
+            }
+        }
+    }
 }
diff --git a/tests/tests/admin/Android.mk b/tests/tests/admin/Android.mk
deleted file mode 100644
index 7a5ae34..0000000
--- a/tests/tests/admin/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner mockito-target
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsAdminTestCases
-
-LOCAL_INSTRUMENTATION_FOR := CtsDeviceAdmin
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/admin/AndroidManifest.xml b/tests/tests/admin/AndroidManifest.xml
deleted file mode 100644
index bbd7918..0000000
--- a/tests/tests/admin/AndroidManifest.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.admin">
-
-  <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-  <application>
-
-      <uses-library android:name="android.test.runner"/>
-
-  </application>
-
-  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                   android:targetPackage="android.deviceadmin.cts"
-                   android:label="Tests for the admin APIs.">
-        <meta-data android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
-    </instrumentation>
-
-</manifest>
diff --git a/tests/tests/admin/AndroidTest.xml b/tests/tests/admin/AndroidTest.xml
deleted file mode 100644
index c29d404..0000000
--- a/tests/tests/admin/AndroidTest.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="CTS device admin test config">
-    <include name="common-config" />
-    <option name="run-command:run-command" value="dpm set-active-admin android.deviceadmin.cts/.CtsDeviceAdminReceiver" />
-    <option name="run-command:run-command" value="dpm set-active-admin android.deviceadmin.cts/.CtsDeviceAdminReceiver2" />
-</configuration>
diff --git a/tests/tests/admin/src/android/admin/cts/DeviceAdminActivationTest.java b/tests/tests/admin/src/android/admin/cts/DeviceAdminActivationTest.java
deleted file mode 100644
index 6fcd0de..0000000
--- a/tests/tests/admin/src/android/admin/cts/DeviceAdminActivationTest.java
+++ /dev/null
@@ -1,204 +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 android.admin.cts;
-
-import android.app.Activity;
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.deviceadmin.cts.CtsDeviceAdminBrokenReceiver;
-import android.deviceadmin.cts.CtsDeviceAdminBrokenReceiver2;
-import android.deviceadmin.cts.CtsDeviceAdminBrokenReceiver3;
-import android.deviceadmin.cts.CtsDeviceAdminBrokenReceiver4;
-import android.deviceadmin.cts.CtsDeviceAdminBrokenReceiver5;
-import android.deviceadmin.cts.CtsDeviceAdminDeactivatedReceiver;
-import android.deviceadmin.cts.CtsDeviceAdminActivationTestActivity;
-import android.deviceadmin.cts.CtsDeviceAdminActivationTestActivity.OnActivityResultListener;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for the standard way of activating a Device Admin: by starting system UI via an
- * {@link Intent} with {@link DevicePolicyManager#ACTION_ADD_DEVICE_ADMIN}. The test requires that
- * the {@code CtsDeviceAdmin.apk} be installed.
- */
-public class DeviceAdminActivationTest
-    extends ActivityInstrumentationTestCase2<CtsDeviceAdminActivationTestActivity> {
-
-    private static final String TAG = DeviceAdminActivationTest.class.getSimpleName();
-
-    // IMPLEMENTATION NOTE: Because Device Admin activation requires the use of
-    // Activity.startActivityForResult, this test creates an empty Activity which then invokes
-    // startActivityForResult.
-
-    private static final int REQUEST_CODE_ACTIVATE_ADMIN = 1;
-
-    /**
-     * Maximum duration of time (milliseconds) after which the effects of programmatic actions in
-     * this test should have affected the UI.
-     */
-    private static final int UI_EFFECT_TIMEOUT_MILLIS = 5000;
-
-    private boolean mDeviceAdmin;
-    @Mock private OnActivityResultListener mMockOnActivityResultListener;
-
-    public DeviceAdminActivationTest() {
-        super(CtsDeviceAdminActivationTestActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        MockitoAnnotations.initMocks(this);
-        getActivity().setOnActivityResultListener(mMockOnActivityResultListener);
-        mDeviceAdmin = getInstrumentation().getContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_DEVICE_ADMIN);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        try {
-            finishActivateDeviceAdminActivity();
-        } finally {
-            super.tearDown();
-        }
-    }
-
-    public void testActivateGoodReceiverDisplaysActivationUi() throws Exception {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testActivateGoodReceiverDisplaysActivationUi");
-            return;
-        }
-        assertDeviceAdminDeactivated(CtsDeviceAdminDeactivatedReceiver.class);
-        startAddDeviceAdminActivityForResult(CtsDeviceAdminDeactivatedReceiver.class);
-        assertWithTimeoutOnActivityResultNotInvoked();
-        // The UI is up and running. Assert that dismissing the UI returns the corresponding result
-        // to the test activity.
-        finishActivateDeviceAdminActivity();
-        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
-        assertDeviceAdminDeactivated(CtsDeviceAdminDeactivatedReceiver.class);
-    }
-
-    public void testActivateBrokenReceiverFails() throws Exception {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testActivateBrokenReceiverFails");
-            return;
-        }
-        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver.class);
-        startAddDeviceAdminActivityForResult(CtsDeviceAdminBrokenReceiver.class);
-        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
-        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver.class);
-    }
-
-    public void testActivateBrokenReceiver2Fails() throws Exception {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testActivateBrokenReceiver2Fails");
-            return;
-        }
-        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver2.class);
-        startAddDeviceAdminActivityForResult(CtsDeviceAdminBrokenReceiver2.class);
-        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
-        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver2.class);
-    }
-
-    public void testActivateBrokenReceiver3Fails() throws Exception {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testActivateBrokenReceiver3Fails");
-            return;
-        }
-        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver3.class);
-        startAddDeviceAdminActivityForResult(CtsDeviceAdminBrokenReceiver3.class);
-        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
-        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver3.class);
-    }
-
-    public void testActivateBrokenReceiver4Fails() throws Exception {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testActivateBrokenReceiver4Fails");
-            return;
-        }
-        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver4.class);
-        startAddDeviceAdminActivityForResult(CtsDeviceAdminBrokenReceiver4.class);
-        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
-        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver4.class);
-    }
-
-    public void testActivateBrokenReceiver5Fails() throws Exception {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testActivateBrokenReceiver5Fails");
-            return;
-        }
-        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver5.class);
-        startAddDeviceAdminActivityForResult(CtsDeviceAdminBrokenReceiver5.class);
-        assertWithTimeoutOnActivityResultInvokedWithResultCode(Activity.RESULT_CANCELED);
-        assertDeviceAdminDeactivated(CtsDeviceAdminBrokenReceiver5.class);
-    }
-
-    private void startAddDeviceAdminActivityForResult(Class<?> receiverClass) {
-        getActivity().startActivityForResult(
-                getAddDeviceAdminIntent(receiverClass),
-                REQUEST_CODE_ACTIVATE_ADMIN);
-    }
-
-    private Intent getAddDeviceAdminIntent(Class<?> receiverClass) {
-        return new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
-            .putExtra(
-                    DevicePolicyManager.EXTRA_DEVICE_ADMIN,
-                    new ComponentName(
-                            getInstrumentation().getTargetContext(),
-                            receiverClass));
-    }
-
-    private void assertWithTimeoutOnActivityResultNotInvoked() {
-        SystemClock.sleep(UI_EFFECT_TIMEOUT_MILLIS);
-        Mockito.verify(mMockOnActivityResultListener, Mockito.never())
-                .onActivityResult(
-                        Mockito.eq(REQUEST_CODE_ACTIVATE_ADMIN),
-                        Mockito.anyInt(),
-                        Mockito.any(Intent.class));
-    }
-
-    private void assertWithTimeoutOnActivityResultInvokedWithResultCode(int expectedResultCode) {
-        ArgumentCaptor<Integer> resultCodeCaptor = ArgumentCaptor.forClass(int.class);
-        Mockito.verify(mMockOnActivityResultListener, Mockito.timeout(UI_EFFECT_TIMEOUT_MILLIS))
-                .onActivityResult(
-                        Mockito.eq(REQUEST_CODE_ACTIVATE_ADMIN),
-                        resultCodeCaptor.capture(),
-                        Mockito.any(Intent.class));
-        assertEquals(expectedResultCode, (int) resultCodeCaptor.getValue());
-    }
-
-    private void finishActivateDeviceAdminActivity() {
-        getActivity().finishActivity(REQUEST_CODE_ACTIVATE_ADMIN);
-    }
-
-    private void assertDeviceAdminDeactivated(Class<?> receiverClass) {
-        DevicePolicyManager devicePolicyManager =
-                (DevicePolicyManager) getActivity().getSystemService(
-                        Context.DEVICE_POLICY_SERVICE);
-        assertFalse(devicePolicyManager.isAdminActive(
-                new ComponentName(getInstrumentation().getTargetContext(), receiverClass)));
-    }
-}
diff --git a/tests/tests/admin/src/android/admin/cts/DeviceAdminInfoTest.java b/tests/tests/admin/src/android/admin/cts/DeviceAdminInfoTest.java
deleted file mode 100644
index fe68073..0000000
--- a/tests/tests/admin/src/android/admin/cts/DeviceAdminInfoTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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 android.admin.cts;
-
-import android.app.admin.DeviceAdminInfo;
-import android.content.ComponentName;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-public class DeviceAdminInfoTest extends AndroidTestCase {
-
-    private static final String TAG = DeviceAdminInfoTest.class.getSimpleName();
-
-    private PackageManager mPackageManager;
-    private ComponentName mComponent;
-    private ComponentName mSecondComponent;
-    private boolean mDeviceAdmin;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mPackageManager = mContext.getPackageManager();
-        mComponent = getReceiverComponent();
-        mSecondComponent = getSecondReceiverComponent();
-        mDeviceAdmin =
-                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
-    }
-
-    static ComponentName getReceiverComponent() {
-        return new ComponentName("android.deviceadmin.cts",
-                "android.deviceadmin.cts.CtsDeviceAdminReceiver");
-    }
-
-    static ComponentName getSecondReceiverComponent() {
-        return new ComponentName("android.deviceadmin.cts",
-                "android.deviceadmin.cts.CtsDeviceAdminReceiver2");
-    }
-
-    public void testDeviceAdminInfo() throws Exception {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testDeviceAdminInfo");
-            return;
-        }
-        ResolveInfo resolveInfo = new ResolveInfo();
-        resolveInfo.activityInfo = mPackageManager.getReceiverInfo(mComponent,
-                PackageManager.GET_META_DATA);
-
-        DeviceAdminInfo info = new DeviceAdminInfo(mContext, resolveInfo);
-        assertEquals(mComponent, info.getComponent());
-        assertEquals(mComponent.getPackageName(), info.getPackageName());
-        assertEquals(mComponent.getClassName(), info.getReceiverName());
-
-        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_FORCE_LOCK));
-        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD));
-        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_RESET_PASSWORD));
-        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_WATCH_LOGIN));
-        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_WIPE_DATA));
-
-        assertEquals("force-lock",
-                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_FORCE_LOCK));
-        assertEquals("limit-password",
-                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD));
-        assertEquals("reset-password",
-                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_RESET_PASSWORD));
-        assertEquals("watch-login",
-                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_WATCH_LOGIN));
-        assertEquals("wipe-data",
-                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_WIPE_DATA));
-    }
-
-    public void testDeviceAdminInfo2() throws Exception {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testDeviceAdminInfo2");
-            return;
-        }
-        ResolveInfo resolveInfo = new ResolveInfo();
-        resolveInfo.activityInfo = mPackageManager.getReceiverInfo(mSecondComponent,
-                PackageManager.GET_META_DATA);
-
-        DeviceAdminInfo info = new DeviceAdminInfo(mContext, resolveInfo);
-        assertEquals(mSecondComponent, info.getComponent());
-        assertEquals(mSecondComponent.getPackageName(), info.getPackageName());
-        assertEquals(mSecondComponent.getClassName(), info.getReceiverName());
-
-        assertFalse(info.usesPolicy(DeviceAdminInfo.USES_POLICY_FORCE_LOCK));
-        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD));
-        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_RESET_PASSWORD));
-        assertFalse(info.usesPolicy(DeviceAdminInfo.USES_POLICY_WATCH_LOGIN));
-        assertTrue(info.usesPolicy(DeviceAdminInfo.USES_POLICY_WIPE_DATA));
-
-        assertEquals("force-lock",
-                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_FORCE_LOCK));
-        assertEquals("limit-password",
-                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD));
-        assertEquals("reset-password",
-                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_RESET_PASSWORD));
-        assertEquals("watch-login",
-                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_WATCH_LOGIN));
-        assertEquals("wipe-data",
-                info.getTagForPolicy(DeviceAdminInfo.USES_POLICY_WIPE_DATA));
-    }
-}
diff --git a/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
deleted file mode 100644
index 66e12c0..0000000
--- a/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ /dev/null
@@ -1,1139 +0,0 @@
-/*
- * 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 android.admin.cts;
-
-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.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.os.Build;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.util.List;
-
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
-
-/**
- * Test that exercises {@link DevicePolicyManager}. The test requires that the
- * CtsDeviceAdminReceiver be installed via the CtsDeviceAdmin.apk and be
- * activated via "Settings > Location & security > Select device administrators".
- */
-public class DevicePolicyManagerTest extends AndroidTestCase {
-
-    private static final String TAG = DevicePolicyManagerTest.class.getSimpleName();
-
-    private DevicePolicyManager mDevicePolicyManager;
-    private ComponentName mComponent;
-    private ComponentName mSecondComponent;
-    private boolean mDeviceAdmin;
-    private boolean mManagedProfiles;
-    private PackageManager mPackageManager;
-
-    private static final String TEST_CA_STRING1 =
-            "-----BEGIN CERTIFICATE-----\n" +
-            "MIICVzCCAgGgAwIBAgIJAMvnLHnnfO/IMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD\n" +
-            "VQQGEwJJTjELMAkGA1UECAwCQVAxDDAKBgNVBAcMA0hZRDEVMBMGA1UECgwMSU1G\n" +
-            "TCBQVlQgTFREMRAwDgYDVQQLDAdJTUZMIE9VMRIwEAYDVQQDDAlJTUZMLklORk8x\n" +
-            "HzAdBgkqhkiG9w0BCQEWEHJhbWVzaEBpbWZsLmluZm8wHhcNMTMwODI4MDk0NDA5\n" +
-            "WhcNMjMwODI2MDk0NDA5WjCBhjELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAkFQMQww\n" +
-            "CgYDVQQHDANIWUQxFTATBgNVBAoMDElNRkwgUFZUIExURDEQMA4GA1UECwwHSU1G\n" +
-            "TCBPVTESMBAGA1UEAwwJSU1GTC5JTkZPMR8wHQYJKoZIhvcNAQkBFhByYW1lc2hA\n" +
-            "aW1mbC5pbmZvMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ738cbTQlNIO7O6nV/f\n" +
-            "DJTMvWbPkyHYX8CQ7yXiAzEiZ5bzKJjDJmpRAkUrVinljKns2l6C4++l/5A7pFOO\n" +
-            "33kCAwEAAaNQME4wHQYDVR0OBBYEFOdbZP7LaMbgeZYPuds2CeSonmYxMB8GA1Ud\n" +
-            "IwQYMBaAFOdbZP7LaMbgeZYPuds2CeSonmYxMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" +
-            "hvcNAQEFBQADQQBdrk6J9koyylMtl/zRfiMAc2zgeC825fgP6421NTxs1rjLs1HG\n" +
-            "VcUyQ1/e7WQgOaBHi9TefUJi+4PSVSluOXon\n" +
-            "-----END CERTIFICATE-----";
-
-    private static final String MANAGED_PROVISIONING_PKG = "com.android.managedprovisioning";
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mDevicePolicyManager = (DevicePolicyManager)
-                mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        mComponent = DeviceAdminInfoTest.getReceiverComponent();
-        mPackageManager = mContext.getPackageManager();
-        mSecondComponent = DeviceAdminInfoTest.getSecondReceiverComponent();
-        mDeviceAdmin = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
-        mManagedProfiles = mDeviceAdmin
-                && mPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS);
-        setBlankPassword();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        setBlankPassword();
-    }
-
-    private void setBlankPassword() {
-        if (!mDeviceAdmin) {
-            return;
-        }
-        // Reset the password to nothing for future tests...
-        mDevicePolicyManager.setPasswordQuality(mComponent,
-                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
-        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 0);
-        assertTrue(mDevicePolicyManager.resetPassword("", 0));
-    }
-
-    public void testGetActiveAdmins() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testGetActiveAdmins");
-            return;
-        }
-        List<ComponentName> activeAdmins = mDevicePolicyManager.getActiveAdmins();
-        assertFalse(activeAdmins.isEmpty());
-        assertTrue(activeAdmins.contains(mComponent));
-        assertTrue(mDevicePolicyManager.isAdminActive(mComponent));
-    }
-
-    public void testGetMaximumFailedPasswordsForWipe() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testGetMaximumFailedPasswordsForWipe");
-            return;
-        }
-        mDevicePolicyManager.setMaximumFailedPasswordsForWipe(mComponent, 3);
-        assertEquals(3, mDevicePolicyManager.getMaximumFailedPasswordsForWipe(mComponent));
-
-        mDevicePolicyManager.setMaximumFailedPasswordsForWipe(mComponent, 5);
-        assertEquals(5, mDevicePolicyManager.getMaximumFailedPasswordsForWipe(mComponent));
-    }
-
-    public void testPasswordQuality_something() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordQuality_something");
-            return;
-        }
-        mDevicePolicyManager.setPasswordQuality(mComponent,
-                DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
-                mDevicePolicyManager.getPasswordQuality(mComponent));
-        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
-
-        String caseDescription = "initial";
-        assertPasswordSucceeds("1234", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordSucceeds("abcd1234", caseDescription);
-
-        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 10);
-        caseDescription = "minimum password length = 10";
-        assertEquals(10, mDevicePolicyManager.getPasswordMinimumLength(mComponent));
-        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
-
-        assertPasswordFails("1234", caseDescription);
-        assertPasswordFails("abcd", caseDescription);
-        assertPasswordFails("abcd1234", caseDescription);
-
-        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 4);
-        caseDescription = "minimum password length = 4";
-        assertEquals(4, mDevicePolicyManager.getPasswordMinimumLength(
-                mComponent));
-        assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
-
-        assertPasswordSucceeds("1234", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordSucceeds("abcd1234", caseDescription);
-    }
-
-    public void testPasswordQuality_numeric() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordQuality_numeric");
-            return;
-        }
-        mDevicePolicyManager.setPasswordQuality(mComponent,
-                DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
-                mDevicePolicyManager.getPasswordQuality(mComponent));
-        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
-
-        String caseDescription = "initial";
-        assertPasswordSucceeds("1234", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordSucceeds("abcd1234", caseDescription);
-
-        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 10);
-        caseDescription = "minimum password length = 10";
-        assertEquals(10, mDevicePolicyManager.getPasswordMinimumLength(mComponent));
-        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
-
-        assertPasswordFails("1234", caseDescription);
-        assertPasswordFails("abcd", caseDescription);
-        assertPasswordFails("abcd1234", caseDescription);
-
-        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 4);
-        caseDescription = "minimum password length = 4";
-        assertEquals(4, mDevicePolicyManager.getPasswordMinimumLength(
-                mComponent));
-        assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
-
-        assertPasswordSucceeds("1234", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordSucceeds("abcd1234", caseDescription);
-    }
-
-    public void testPasswordQuality_alphabetic() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordQuality_alphabetic");
-            return;
-        }
-        mDevicePolicyManager.setPasswordQuality(mComponent,
-                DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
-                mDevicePolicyManager.getPasswordQuality(mComponent));
-        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
-
-        String caseDescription = "initial";
-        assertPasswordFails("1234", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordSucceeds("abcd1234", caseDescription);
-
-        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 10);
-        caseDescription = "minimum password length = 10";
-        assertEquals(10, mDevicePolicyManager.getPasswordMinimumLength(mComponent));
-        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
-
-        assertPasswordFails("1234", caseDescription);
-        assertPasswordFails("abcd", caseDescription);
-        assertPasswordFails("abcd1234", caseDescription);
-
-        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 4);
-        caseDescription = "minimum password length = 4";
-        assertEquals(4, mDevicePolicyManager.getPasswordMinimumLength(
-                mComponent));
-        assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
-
-        assertPasswordFails("1234", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordSucceeds("abcd1234", caseDescription);
-    }
-
-    public void testPasswordQuality_alphanumeric() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordQuality_alphanumeric");
-            return;
-        }
-        mDevicePolicyManager.setPasswordQuality(mComponent,
-                DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
-                mDevicePolicyManager.getPasswordQuality(mComponent));
-        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
-
-        String caseDescription = "initial";
-        assertPasswordFails("1234", caseDescription);
-        assertPasswordFails("abcd", caseDescription);
-        assertPasswordSucceeds("abcd1234", caseDescription);
-
-        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 10);
-        caseDescription = "minimum password length = 10";
-        assertEquals(10, mDevicePolicyManager.getPasswordMinimumLength(mComponent));
-        assertFalse(mDevicePolicyManager.isActivePasswordSufficient());
-
-        assertPasswordFails("1234", caseDescription);
-        assertPasswordFails("abcd", caseDescription);
-        assertPasswordFails("abcd1234", caseDescription);
-
-        mDevicePolicyManager.setPasswordMinimumLength(mComponent, 4);
-        caseDescription = "minimum password length = 4";
-        assertEquals(4, mDevicePolicyManager.getPasswordMinimumLength(
-                mComponent));
-        assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
-
-        assertPasswordFails("1234", caseDescription);
-        assertPasswordFails("abcd", caseDescription);
-        assertPasswordSucceeds("abcd1234", caseDescription);
-    }
-
-    public void testPasswordQuality_complexUpperCase() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordQuality_complexUpperCase");
-            return;
-        }
-
-        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
-        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
-        resetComplexPasswordRestrictions();
-
-        String caseDescription = "minimum UpperCase=0";
-        assertPasswordSucceeds("abc1", caseDescription);
-        assertPasswordSucceeds("aBc1", caseDescription);
-        assertPasswordSucceeds("ABC1", caseDescription);
-        assertPasswordSucceeds("ABCD", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumUpperCase(mComponent, 1);
-        assertEquals(1, mDevicePolicyManager.getPasswordMinimumUpperCase(mComponent));
-        caseDescription = "minimum UpperCase=1";
-        assertPasswordFails("abc1", caseDescription);
-        assertPasswordSucceeds("aBc1", caseDescription);
-        assertPasswordSucceeds("ABC1", caseDescription);
-        assertPasswordSucceeds("ABCD", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumUpperCase(mComponent, 3);
-        assertEquals(3, mDevicePolicyManager.getPasswordMinimumUpperCase(mComponent));
-        caseDescription = "minimum UpperCase=3";
-        assertPasswordFails("abc1", caseDescription);
-        assertPasswordFails("aBC1", caseDescription);
-        assertPasswordSucceeds("ABC1", caseDescription);
-        assertPasswordSucceeds("ABCD", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-    }
-
-    public void testPasswordQuality_complexLowerCase() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordQuality_complexLowerCase");
-            return;
-        }
-
-        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
-        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
-        resetComplexPasswordRestrictions();
-
-        String caseDescription = "minimum LowerCase=0";
-        assertPasswordSucceeds("ABCD", caseDescription);
-        assertPasswordSucceeds("aBC1", caseDescription);
-        assertPasswordSucceeds("abc1", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumLowerCase(mComponent, 1);
-        assertEquals(1, mDevicePolicyManager.getPasswordMinimumLowerCase(mComponent));
-        caseDescription = "minimum LowerCase=1";
-        assertPasswordFails("ABCD", caseDescription);
-        assertPasswordSucceeds("aBC1", caseDescription);
-        assertPasswordSucceeds("abc1", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumLowerCase(mComponent, 3);
-        assertEquals(3, mDevicePolicyManager.getPasswordMinimumLowerCase(mComponent));
-        caseDescription = "minimum LowerCase=3";
-        assertPasswordFails("ABCD", caseDescription);
-        assertPasswordFails("aBC1", caseDescription);
-        assertPasswordSucceeds("abc1", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-    }
-
-    public void testPasswordQuality_complexLetters() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordQuality_complexLetters");
-            return;
-        }
-
-        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
-        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
-        resetComplexPasswordRestrictions();
-
-        String caseDescription = "minimum Letters=0";
-        assertPasswordSucceeds("1234", caseDescription);
-        assertPasswordSucceeds("a123", caseDescription);
-        assertPasswordSucceeds("abc1", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumLetters(mComponent, 1);
-        assertEquals(1, mDevicePolicyManager.getPasswordMinimumLetters(mComponent));
-        caseDescription = "minimum Letters=1";
-        assertPasswordFails("1234", caseDescription);
-        assertPasswordSucceeds("a123", caseDescription);
-        assertPasswordSucceeds("abc1", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumLetters(mComponent, 3);
-        assertEquals(3, mDevicePolicyManager.getPasswordMinimumLetters(mComponent));
-        caseDescription = "minimum Letters=3";
-        assertPasswordFails("1234", caseDescription);
-        assertPasswordFails("a123", caseDescription);
-        assertPasswordSucceeds("abc1", caseDescription);
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-    }
-
-    public void testPasswordQuality_complexNumeric() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordQuality_complexNumeric");
-            return;
-        }
-
-        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
-        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
-        resetComplexPasswordRestrictions();
-
-        String caseDescription = "minimum Numeric=0";
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordSucceeds("1abc", caseDescription);
-        assertPasswordSucceeds("123a", caseDescription);
-        assertPasswordSucceeds("1234", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumNumeric(mComponent, 1);
-        assertEquals(1, mDevicePolicyManager.getPasswordMinimumNumeric(mComponent));
-        caseDescription = "minimum Numeric=1";
-        assertPasswordFails("abcd", caseDescription);
-        assertPasswordSucceeds("1abc", caseDescription);
-        assertPasswordSucceeds("123a", caseDescription);
-        assertPasswordSucceeds("1234", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumNumeric(mComponent, 3);
-        assertEquals(3, mDevicePolicyManager.getPasswordMinimumNumeric(mComponent));
-        caseDescription = "minimum Numeric=3";
-        assertPasswordFails("abcd", caseDescription);
-        assertPasswordFails("1abc", caseDescription);
-        assertPasswordSucceeds("123a", caseDescription);
-        assertPasswordSucceeds("1234", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-    }
-
-    public void testPasswordQuality_complexSymbols() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordQuality_complexSymbols");
-            return;
-        }
-
-        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
-        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
-        resetComplexPasswordRestrictions();
-
-        String caseDescription = "minimum Symbols=0";
-        assertPasswordSucceeds("abcd", caseDescription);
-        assertPasswordSucceeds("_bc1", caseDescription);
-        assertPasswordSucceeds("@#!1", caseDescription);
-        assertPasswordSucceeds("_@#!", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumSymbols(mComponent, 1);
-        assertEquals(1, mDevicePolicyManager.getPasswordMinimumSymbols(mComponent));
-        caseDescription = "minimum Symbols=1";
-        assertPasswordFails("abcd", caseDescription);
-        assertPasswordSucceeds("_bc1", caseDescription);
-        assertPasswordSucceeds("@#!1", caseDescription);
-        assertPasswordSucceeds("_@#!", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumSymbols(mComponent, 3);
-        assertEquals(3, mDevicePolicyManager.getPasswordMinimumSymbols(mComponent));
-        caseDescription = "minimum Symbols=3";
-        assertPasswordFails("abcd", caseDescription);
-        assertPasswordFails("_bc1", caseDescription);
-        assertPasswordSucceeds("@#!1", caseDescription);
-        assertPasswordSucceeds("_@#!", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-    }
-
-    public void testPasswordQuality_complexNonLetter() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordQuality_complexNonLetter");
-            return;
-        }
-
-        mDevicePolicyManager.setPasswordQuality(mComponent, PASSWORD_QUALITY_COMPLEX);
-        assertEquals(PASSWORD_QUALITY_COMPLEX, mDevicePolicyManager.getPasswordQuality(mComponent));
-        resetComplexPasswordRestrictions();
-
-        String caseDescription = "minimum NonLetter=0";
-        assertPasswordSucceeds("Abcd", caseDescription);
-        assertPasswordSucceeds("_bcd", caseDescription);
-        assertPasswordSucceeds("3bcd", caseDescription);
-        assertPasswordSucceeds("_@3c", caseDescription);
-        assertPasswordSucceeds("_25!", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumNonLetter(mComponent, 1);
-        assertEquals(1, mDevicePolicyManager.getPasswordMinimumNonLetter(mComponent));
-        caseDescription = "minimum NonLetter=1";
-        assertPasswordFails("Abcd", caseDescription);
-        assertPasswordSucceeds("_bcd", caseDescription);
-        assertPasswordSucceeds("3bcd", caseDescription);
-        assertPasswordSucceeds("_@3c", caseDescription);
-        assertPasswordSucceeds("_25!", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-
-        mDevicePolicyManager.setPasswordMinimumNonLetter(mComponent, 3);
-        assertEquals(3, mDevicePolicyManager.getPasswordMinimumNonLetter(mComponent));
-        caseDescription = "minimum NonLetter=3";
-        assertPasswordFails("Abcd", caseDescription);
-        assertPasswordFails("_bcd", caseDescription);
-        assertPasswordFails("3bcd", caseDescription);
-        assertPasswordSucceeds("_@3c", caseDescription);
-        assertPasswordSucceeds("_25!", caseDescription);
-        assertPasswordFails("123", caseDescription); // too short
-    }
-
-    public void testPasswordHistoryLength() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordHistoryLength");
-            return;
-        }
-        // Password history length restriction is only imposed if password quality is at least
-        // numeric.
-        mDevicePolicyManager.setPasswordQuality(mComponent,
-                DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
-        int originalValue = mDevicePolicyManager.getPasswordHistoryLength(mComponent);
-        try {
-            mDevicePolicyManager.setPasswordHistoryLength(mComponent, 3);
-            assertEquals(3, mDevicePolicyManager.getPasswordHistoryLength(mComponent));
-            // Although it would make sense we cannot test if password history restrictions
-            // are enforced as DevicePolicyManagerService.resetPassword fails to do so at the
-            // moment. See b/17707820
-        } finally {
-            mDevicePolicyManager.setPasswordHistoryLength(mComponent, originalValue);
-        }
-    }
-
-    public void testPasswordExpirationTimeout() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testPasswordExpirationTimeout");
-            return;
-        }
-        long originalValue = mDevicePolicyManager.getPasswordExpirationTimeout(mComponent);
-        try {
-            for (long testLength : new long[] {
-                    0L, 864000000L /* ten days */, 8640000000L /* 100 days */}) {
-                mDevicePolicyManager.setPasswordExpirationTimeout(mComponent, testLength);
-                assertEquals(testLength,
-                        mDevicePolicyManager.getPasswordExpirationTimeout(mComponent));
-            }
-        } finally {
-            mDevicePolicyManager.setPasswordExpirationTimeout(mComponent, originalValue);
-        }
-    }
-
-    public void testKeyguardDisabledFeatures() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testKeyguardDisabledFeatures");
-            return;
-        }
-        int originalValue = mDevicePolicyManager.getKeyguardDisabledFeatures(mComponent);
-        try {
-            for (int which = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
-                    which < 2 * DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; ++which) {
-                mDevicePolicyManager.setKeyguardDisabledFeatures(mComponent, which);
-                assertEquals(which, mDevicePolicyManager.getKeyguardDisabledFeatures(mComponent));
-            }
-        } finally {
-            mDevicePolicyManager.setKeyguardDisabledFeatures(mComponent, originalValue);
-        }
-    }
-
-    public void testCreateUser_failIfNotDeviceOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testCreateUser_failIfNotDeviceOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.createUser(mComponent, "user name");
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertDeviceOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testRemoveUser_failIfNotDeviceOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testRemoveUser_failIfNotDeviceOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.removeUser(mComponent, null);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertDeviceOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetApplicationHidden_failIfNotDeviceOrProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetApplicationHidden_failIfNotDeviceOrProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setApplicationHidden(mComponent, "com.google.anything", true);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testIsApplicationHidden_failIfNotDeviceOrProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testIsApplicationHidden_failIfNotDeviceOrProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.isApplicationHidden(mComponent, "com.google.anything");
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetGlobalSetting_failIfNotDeviceOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetGlobalSetting_failIfNotDeviceOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setGlobalSetting(mComponent,
-                    Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, "1");
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertDeviceOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetSecureSetting_failIfNotDeviceOrProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetSecureSetting_failIfNotDeviceOrProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setSecureSetting(mComponent,
-                    Settings.Secure.INSTALL_NON_MARKET_APPS, "1");
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetMasterVolumeMuted_failIfNotDeviceOrProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetMasterVolumeMuted_failIfNotDeviceOrProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setMasterVolumeMuted(mComponent, true);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testIsMasterVolumeMuted_failIfNotDeviceOrProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetMasterVolumeMuted_failIfNotDeviceOrProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.isMasterVolumeMuted(mComponent);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetRecommendedGlobalProxy_failIfNotDeviceOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetRecommendedGlobalProxy_failIfNotDeviceOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setRecommendedGlobalProxy(mComponent, null);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertDeviceOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetLockTaskPackages_failIfNotDeviceOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetLockTaskPackages_failIfNotDeviceOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setLockTaskPackages(mComponent, new String[] {"package"});
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-        }
-    }
-
-    public void testClearDeviceOwnerApp_failIfNotDeviceOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testClearDeviceOwnerApp_failIfNotDeviceOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.clearDeviceOwnerApp("android.deviceadmin.cts");
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertDeviceOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSwitchUser_failIfNotDeviceOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSwitchUser_failIfNotDeviceOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.switchUser(mComponent, null);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertDeviceOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testCreateAndInitializeUser_failIfNotDeviceOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testCreateAndInitializeUser_failIfNotDeviceOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.createAndInitializeUser(mComponent, "name", "admin name",
-                        mComponent, null);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertDeviceOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testInstallCaCert_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testInstallCaCert_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.installCaCert(mComponent,
-                    TEST_CA_STRING1.getBytes());
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testInstallCaCert_failIfNotCertInstaller() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testInstallCaCert_failIfNotCertInstaller");
-            return;
-        }
-        try {
-            // Delegated cert installer is identified by using null as the first argument.
-            mDevicePolicyManager.installCaCert(null, TEST_CA_STRING1.getBytes());
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException expected) {
-        }
-    }
-
-    public void testUninstallCaCert_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testUninstallCaCert_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.uninstallCaCert(mComponent,
-                    TEST_CA_STRING1.getBytes());
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testUninstallCaCert_failIfNotCertInstaller() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testUninstallCaCert_failIfNotCertInstaller");
-            return;
-        }
-        try {
-            // Delegated cert installer is identified by using null as the first argument.
-            mDevicePolicyManager.uninstallCaCert(null, TEST_CA_STRING1.getBytes());
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException expected) {
-        }
-    }
-
-    public void testGetInstalledCaCerts_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testGetInstalledCaCerts_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.getInstalledCaCerts(mComponent);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testGetInstalledCaCerts_failIfNotCertInstaller() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testGetInstalledCaCerts_failIfNotCertInstaller");
-            return;
-        }
-        try {
-            // Delegated cert installer is identified by using null as the first argument.
-            mDevicePolicyManager.getInstalledCaCerts(null);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException expected) {
-        }
-    }
-
-    public void testHasCaCertInstalled_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testHasCaCertInstalled_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.hasCaCertInstalled(mComponent,
-                    TEST_CA_STRING1.getBytes());
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testHasCaCertInstalled_failIfNotCertInstaller() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testHasCaCertInstalled_failIfNotCertInstaller");
-            return;
-        }
-        try {
-            // Delegated cert installer is identified by using null as the first argument.
-            mDevicePolicyManager.hasCaCertInstalled(null, TEST_CA_STRING1.getBytes());
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException expected) {
-        }
-    }
-
-    public void testUninstallAllUserCaCerts_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testUninstallAllUserCaCerts_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.uninstallAllUserCaCerts(mComponent);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testUninstallAllUserCaCerts_failIfNotCertInstaller() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testUninstallAllUserCaCerts_failIfNotCertInstaller");
-            return;
-        }
-        try {
-            // Delegated cert installer is identified by using null as the first argument.
-            mDevicePolicyManager.uninstallAllUserCaCerts(null);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException expected) {
-        }
-    }
-
-    public void testSetScreenCaptureDisabled_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetScreenCaptureDisabled_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setScreenCaptureDisabled(mComponent, true);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetAutoTimeRequired_failIfNotDeviceOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetAutoTimeRequired_failIfNotDeviceOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setAutoTimeRequired(mComponent, true);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertDeviceOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testAddPersistentPreferredActivity_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testAddPersistentPreferredActivity_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.addPersistentPreferredActivity(mComponent,
-                    new IntentFilter(Intent.ACTION_MAIN),
-                    new ComponentName("android.admin.cts", "dummy"));
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testClearPackagePersistentPreferredActivities_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testClearPackagePersistentPreferredActivities_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.clearPackagePersistentPreferredActivities(mComponent,
-                    "android.admin.cts");
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetApplicationRestrictions_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetApplicationRestrictions_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setApplicationRestrictions(mComponent,
-                    "android.admin.cts", null);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testAddUserRestriction_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testAddUserRestriction_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.addUserRestriction(mComponent,
-                    UserManager.DISALLOW_SMS);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetAccountManagementDisabled_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetAccountManagementDisabled_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setAccountManagementDisabled(mComponent,
-                    "dummy", true);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetRestrictionsProvider_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetRestrictionsProvider_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setRestrictionsProvider(mComponent,
-                    new ComponentName("android.admin.cts", "dummy"));
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetUninstallBlocked_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetUninstallBlocked_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setUninstallBlocked(mComponent,
-                    "android.admin.cts", true);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetPermittedAccessibilityServices_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetPermittedAccessibilityServices_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setPermittedAccessibilityServices(mComponent, null);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetBluetoothContactSharingDisabled_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetBluetoothContactSharingDisabled_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setBluetoothContactSharingDisabled(mComponent, true);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetPermittedInputMethods_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetPermittedInputMethods_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setPermittedInputMethods(mComponent, null);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    /**
-     * Test whether the version of the pre-installed launcher is at least L. This is needed for
-     * managed profile support.
-     */
-    public void testLauncherVersionAtLeastL() throws Exception {
-        if (!mManagedProfiles) {
-            return;
-        }
-
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.addCategory(Intent.CATEGORY_HOME);
-        List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
-                0 /* default flags */);
-        assertFalse("No launcher present", resolveInfos.isEmpty());
-
-        for (ResolveInfo resolveInfo : resolveInfos) {
-            ApplicationInfo launcherAppInfo = mPackageManager.getApplicationInfo(
-                    resolveInfo.activityInfo.packageName, 0 /* default flags */);
-            if ((launcherAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 &&
-                    launcherAppInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
-                return;
-            }
-        }
-        fail("No system launcher with version L+ present present on device.");
-    }
-
-    /**
-     * Test that managed provisioning is pre-installed if and only if the device declares the
-     * device admin feature.
-     */
-    public void testManagedProvisioningPreInstalled() throws Exception {
-        assertEquals(mDeviceAdmin, isPackageInstalledOnSystemImage(MANAGED_PROVISIONING_PKG));
-    }
-
-    private void assertDeviceOwnerMessage(String message) {
-        assertTrue("message is: "+ message, message.contains("does not own the device")
-                || message.contains("can only be called by the device owner"));
-    }
-
-    private void assertProfileOwnerMessage(String message) {
-        assertTrue("message is: "+ message,
-                message.contains("does not own the profile"));
-    }
-
-    private void resetComplexPasswordRestrictions() {
-        /**
-         * Not enough to reset only mComponent as
-         * {@link DevicePolicyManager#resetPassword(String, int)} checks restrictions across all
-         * admin components.
-         */
-        for (ComponentName adminComponent : new ComponentName[] {mComponent, mSecondComponent}) {
-            mDevicePolicyManager.setPasswordMinimumLength(adminComponent, 0);
-            mDevicePolicyManager.setPasswordMinimumUpperCase(adminComponent, 0);
-            mDevicePolicyManager.setPasswordMinimumLowerCase(adminComponent, 0);
-            mDevicePolicyManager.setPasswordMinimumLetters(adminComponent, 0);
-            mDevicePolicyManager.setPasswordMinimumNumeric(adminComponent, 0);
-            mDevicePolicyManager.setPasswordMinimumSymbols(adminComponent, 0);
-            mDevicePolicyManager.setPasswordMinimumNonLetter(adminComponent, 0);
-        }
-    }
-
-    private void assertPasswordFails(String password, String restriction) {
-        try {
-            boolean passwordResetResult = mDevicePolicyManager.resetPassword(password, /* flags= */0);
-            assertFalse("Password '" + password + "' should have failed on " + restriction,
-                    passwordResetResult);
-        } catch (IllegalArgumentException e) {
-            // yesss, we have failed!
-        }
-    }
-
-    private void assertPasswordSucceeds(String password, String restriction) {
-        boolean passwordResetResult = mDevicePolicyManager.resetPassword(password, /* flags= */0);
-        assertTrue("Password '" + password + "' failed on " + restriction, passwordResetResult);
-        assertTrue(mDevicePolicyManager.isActivePasswordSufficient());
-    }
-
-    public void testSetDelegatedCertInstaller_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetDelegatedCertInstaller_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setCertInstallerPackage(mComponent, "com.test.package");
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testGetDelegatedCertInstaller_failIfNotProfileOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testGetDelegatedCertInstaller_failIfNotProfileOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.getCertInstallerPackage(mComponent);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertProfileOwnerMessage(e.getMessage());
-        }
-    }
-
-    public void testSetSystemUpdatePolicy_failIfNotDeviceOwner() {
-        if (!mDeviceAdmin) {
-            Log.w(TAG, "Skipping testSetSystemUpdatePolicy_failIfNotDeviceOwner");
-            return;
-        }
-        try {
-            mDevicePolicyManager.setSystemUpdatePolicy(mComponent, null);
-            fail("did not throw expected SecurityException");
-        } catch (SecurityException e) {
-            assertDeviceOwnerMessage(e.getMessage());
-        }
-    }
-
-    private boolean isPackageInstalledOnSystemImage(String packagename) {
-        try {
-            ApplicationInfo info = mPackageManager.getApplicationInfo(packagename,
-                    0 /* default flags */);
-            return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-        } catch (NameNotFoundException e) {
-            return false;
-        }
-    }
-}
diff --git a/tests/tests/alarmclock/Android.mk b/tests/tests/alarmclock/Android.mk
index 6c30bc7..ee3e015 100644
--- a/tests/tests/alarmclock/Android.mk
+++ b/tests/tests/alarmclock/Android.mk
@@ -29,5 +29,10 @@
 
 LOCAL_SDK_VERSION := current
 
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/alarmclock/AndroidTest.xml b/tests/tests/alarmclock/AndroidTest.xml
index aafdb61..525257e 100644
--- a/tests/tests/alarmclock/AndroidTest.xml
+++ b/tests/tests/alarmclock/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,10 +13,19 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Test module config for AlarmClock">
-    <include name="common-config" />
-    <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockService.apk" />
-    <option name="run-command:run-command"
-         value="settings put secure voice_interaction_service android.alarmclock.service/.MainInteractionService" />
-    <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockTestCases.apk" />
-</configuration>
+<configuration description="Configuration for AlarmClock Tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAlarmClockService.apk" />
+        <option name="test-file-name" value="CtsAlarmClockTestCases.apk" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">    
+        <option name="run-command"
+             value="settings put secure voice_interaction_service android.alarmclock.service/.MainInteractionService" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="android.alarmclock.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/alarmclock/OldAndroidTest.xml b/tests/tests/alarmclock/OldAndroidTest.xml
new file mode 100644
index 0000000..aafdb61
--- /dev/null
+++ b/tests/tests/alarmclock/OldAndroidTest.xml
@@ -0,0 +1,21 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Test module config for AlarmClock">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockService.apk" />
+    <option name="run-command:run-command"
+         value="settings put secure voice_interaction_service android.alarmclock.service/.MainInteractionService" />
+    <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockTestCases.apk" />
+</configuration>
diff --git a/tests/tests/alarmclock/common/Android.mk b/tests/tests/alarmclock/common/Android.mk
index d460ade..d0b7be0 100644
--- a/tests/tests/alarmclock/common/Android.mk
+++ b/tests/tests/alarmclock/common/Android.mk
@@ -27,4 +27,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/tests/alarmclock/service/Android.mk b/tests/tests/alarmclock/service/Android.mk
index 53dc564..3502582 100644
--- a/tests/tests/alarmclock/service/Android.mk
+++ b/tests/tests/alarmclock/service/Android.mk
@@ -29,4 +29,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/animation/Android.mk b/tests/tests/animation/Android.mk
index 3d8daf7..35b9312 100644
--- a/tests/tests/animation/Android.mk
+++ b/tests/tests/animation/Android.mk
@@ -28,6 +28,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/animation/AndroidManifest.xml b/tests/tests/animation/AndroidManifest.xml
index fdc5ad9..3744a2a 100644
--- a/tests/tests/animation/AndroidManifest.xml
+++ b/tests/tests/animation/AndroidManifest.xml
@@ -15,20 +15,22 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.animation">
+    package="android.animation.cts">
     <uses-sdk android:minSdkVersion="11" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
         <activity android:name="android.animation.cts.AnimationActivity"
-            android:label="AnimationActivity"/>
+                  android:label="AnimationActivity"/>
+        <activity android:name="android.animation.cts.ButtonViewActivity"
+                  android:label="ButtonViewActivity"/>
         <activity
            android:name="android.animation.cts.LayoutAnimationActivity" />
         <uses-library android:name="android.test.runner" />
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.animation"
+                     android:targetPackage="android.animation.cts"
                      android:label="CTS tests for android.animation package">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/animation/AndroidTest.xml b/tests/tests/animation/AndroidTest.xml
new file mode 100644
index 0000000..b4a0ad5
--- /dev/null
+++ b/tests/tests/animation/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Animation test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAnimationTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.animation.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/animation/res/animator/object_animator.xml b/tests/tests/animation/res/animator/object_animator.xml
new file mode 100644
index 0000000..17fcd60
--- /dev/null
+++ b/tests/tests/animation/res/animator/object_animator.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+          android:propertyName="x" android:valueFrom="0" android:valueTo="1">
+
+</objectAnimator>
\ No newline at end of file
diff --git a/tests/tests/animation/res/animator/object_animator_pvh1.xml b/tests/tests/animation/res/animator/object_animator_pvh1.xml
new file mode 100644
index 0000000..7e16bc8
--- /dev/null
+++ b/tests/tests/animation/res/animator/object_animator_pvh1.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android">
+    <propertyValuesHolder android:propertyName="x" android:valueFrom="0" android:valueTo="1"/>
+    <propertyValuesHolder android:propertyName="y" android:valueFrom="10" android:valueTo="11"/>
+</objectAnimator>
\ No newline at end of file
diff --git a/tests/tests/animation/res/animator/object_animator_pvh_kf1.xml b/tests/tests/animation/res/animator/object_animator_pvh_kf1.xml
new file mode 100644
index 0000000..b99b819
--- /dev/null
+++ b/tests/tests/animation/res/animator/object_animator_pvh_kf1.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android">
+    <propertyValuesHolder android:propertyName="x" android:valueFrom="0" android:valueTo="1"/>
+    <propertyValuesHolder android:propertyName="y" >
+        <keyframe android:fraction="0" android:value="10"/>
+        <keyframe android:fraction="1" android:value="11"/>
+    </propertyValuesHolder>
+</objectAnimator>
\ No newline at end of file
diff --git a/tests/tests/animation/res/animator/value_animator.xml b/tests/tests/animation/res/animator/value_animator.xml
new file mode 100644
index 0000000..4c1abfe
--- /dev/null
+++ b/tests/tests/animation/res/animator/value_animator.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<animator xmlns:android="http://schemas.android.com/apk/res/android"
+        android:valueFrom="0" android:valueTo="1">
+
+</animator>
\ No newline at end of file
diff --git a/tests/tests/animation/res/animator/value_animator_pvh1.xml b/tests/tests/animation/res/animator/value_animator_pvh1.xml
new file mode 100644
index 0000000..30540ec
--- /dev/null
+++ b/tests/tests/animation/res/animator/value_animator_pvh1.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<animator xmlns:android="http://schemas.android.com/apk/res/android">
+    <propertyValuesHolder android:valueFrom="0" android:valueTo="1"/>
+
+</animator>
\ No newline at end of file
diff --git a/tests/tests/animation/res/animator/value_animator_pvh2.xml b/tests/tests/animation/res/animator/value_animator_pvh2.xml
new file mode 100644
index 0000000..2c07b4e
--- /dev/null
+++ b/tests/tests/animation/res/animator/value_animator_pvh2.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<animator xmlns:android="http://schemas.android.com/apk/res/android">
+    <propertyValuesHolder android:valueFrom="0" android:valueTo="1"></propertyValuesHolder>
+
+</animator>
\ No newline at end of file
diff --git a/tests/tests/animation/res/animator/value_animator_pvh_kf1.xml b/tests/tests/animation/res/animator/value_animator_pvh_kf1.xml
new file mode 100644
index 0000000..e8fb9cc
--- /dev/null
+++ b/tests/tests/animation/res/animator/value_animator_pvh_kf1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<animator xmlns:android="http://schemas.android.com/apk/res/android">
+    <propertyValuesHolder>
+        <keyframe android:fraction="0" android:value="0"/>
+        <keyframe android:fraction="1" android:value="1"/>
+    </propertyValuesHolder>
+</animator>
\ No newline at end of file
diff --git a/tests/tests/animation/res/animator/value_animator_pvh_kf2.xml b/tests/tests/animation/res/animator/value_animator_pvh_kf2.xml
new file mode 100644
index 0000000..be8184f
--- /dev/null
+++ b/tests/tests/animation/res/animator/value_animator_pvh_kf2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<animator xmlns:android="http://schemas.android.com/apk/res/android">
+    <propertyValuesHolder>
+        <keyframe android:fraction="0" android:value="0"></keyframe>
+        <keyframe android:fraction="1" android:value="1"/>
+    </propertyValuesHolder>
+</animator>
\ No newline at end of file
diff --git a/tests/tests/animation/res/animator/value_animator_pvh_kf3.xml b/tests/tests/animation/res/animator/value_animator_pvh_kf3.xml
new file mode 100644
index 0000000..5d6dd4b
--- /dev/null
+++ b/tests/tests/animation/res/animator/value_animator_pvh_kf3.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<animator xmlns:android="http://schemas.android.com/apk/res/android">
+    <propertyValuesHolder>
+        <keyframe android:fraction="0" android:value="0"></keyframe>
+        <keyframe android:fraction=".4" android:value=".2"/>
+        <keyframe android:fraction=".6" android:value=".2"/>
+        <keyframe android:fraction="1" android:value="1"/>
+    </propertyValuesHolder>
+</animator>
\ No newline at end of file
diff --git a/tests/tests/animation/res/animator/value_animator_pvh_kf4.xml b/tests/tests/animation/res/animator/value_animator_pvh_kf4.xml
new file mode 100644
index 0000000..a59fb84
--- /dev/null
+++ b/tests/tests/animation/res/animator/value_animator_pvh_kf4.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<animator xmlns:android="http://schemas.android.com/apk/res/android">
+    <propertyValuesHolder>
+        <keyframe android:value="0"></keyframe>
+        <keyframe android:value=".2"/>
+        <keyframe android:value=".2"/>
+        <keyframe android:value="1"/>
+    </propertyValuesHolder>
+</animator>
\ No newline at end of file
diff --git a/tests/tests/animation/res/layout/button_view.xml b/tests/tests/animation/res/layout/button_view.xml
new file mode 100644
index 0000000..349fedf
--- /dev/null
+++ b/tests/tests/animation/res/layout/button_view.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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="fill_parent"
+              android:layout_height="fill_parent"
+              android:id="@+id/container">
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/button"
+            android:id="@+id/button"/>
+    <View
+            android:layout_width="200dp"
+            android:layout_height="200dp"
+            android:background="#fff"
+            android:id="@+id/square"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/animation/res/values/strings.xml b/tests/tests/animation/res/values/strings.xml
index 8d167fd..587930b 100644
--- a/tests/tests/animation/res/values/strings.xml
+++ b/tests/tests/animation/res/values/strings.xml
@@ -15,4 +15,5 @@
 -->
 <resources>
     <string name="add_button">Add Button</string>
+    <string name="button">Button</string>
 </resources>
diff --git a/tests/tests/animation/src/android/animation/cts/AnimationActivity.java b/tests/tests/animation/src/android/animation/cts/AnimationActivity.java
index 225a97e..598048e 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimationActivity.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimationActivity.java
@@ -39,7 +39,7 @@
 import android.view.animation.AccelerateInterpolator;
 import java.util.ArrayList;
 
-import com.android.cts.animation.R;
+import android.animation.cts.R;
 
 public class AnimationActivity extends Activity {
     private static final String BALL_HEIGHT = "ballwidth";
diff --git a/tests/tests/animation/src/android/animation/cts/ButtonViewActivity.java b/tests/tests/animation/src/android/animation/cts/ButtonViewActivity.java
new file mode 100644
index 0000000..fe66951
--- /dev/null
+++ b/tests/tests/animation/src/android/animation/cts/ButtonViewActivity.java
@@ -0,0 +1,31 @@
+/*
+ * 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.animation.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import android.animation.cts.R;
+
+public class ButtonViewActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.button_view);
+    }
+}
diff --git a/tests/tests/animation/src/android/animation/cts/CreationTest.java b/tests/tests/animation/src/android/animation/cts/CreationTest.java
new file mode 100644
index 0000000..f45f64b
--- /dev/null
+++ b/tests/tests/animation/src/android/animation/cts/CreationTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2015 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.animation.cts;
+
+import android.animation.AnimatorInflater;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.os.Debug;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+
+import android.animation.cts.R;
+
+public class CreationTest extends ActivityInstrumentationTestCase2<ButtonViewActivity> {
+
+    private ButtonViewActivity mActivity;
+
+    public CreationTest() {
+        super(ButtonViewActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setActivityInitialTouchMode(false);
+        mActivity = getActivity();
+    }
+
+    @UiThreadTest
+    public void testValueAnimatorCreation() {
+        ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
+        verifyValues(animator, 0, 1);
+    }
+
+    @UiThreadTest
+    public void testValueAnimatorResourceCreation() {
+        ValueAnimator animator = (ValueAnimator)
+                AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator);
+        verifyValues(animator, 0, 1);
+    }
+
+    @UiThreadTest
+    public void testValueAnimatorPvh1() {
+        ValueAnimator animator = (ValueAnimator)
+                AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh1);
+        verifyValues(animator, 0, 1);
+    }
+
+    @UiThreadTest
+    public void testValueAnimatorPvh2() {
+        ValueAnimator animator = (ValueAnimator)
+                AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh2);
+        verifyValues(animator, 0, 1);
+    }
+
+    @UiThreadTest
+    public void testValueAnimatorPvhKf1() {
+        ValueAnimator animator = (ValueAnimator)
+                AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh_kf1);
+        verifyValues(animator, 0, 1);
+    }
+
+    @UiThreadTest
+    public void testValueAnimatorPvhKf2() {
+        ValueAnimator animator = (ValueAnimator)
+                AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh_kf2);
+        verifyValues(animator, 0, 1);
+    }
+
+    @UiThreadTest
+    public void testValueAnimatorPvhKf3() {
+        ValueAnimator animator = (ValueAnimator)
+                AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh_kf3);
+        verifyValues(animator, 0, .2f, 1);
+    }
+
+    @UiThreadTest
+    public void testValueAnimatorPvhKf4() {
+        ValueAnimator animator = (ValueAnimator)
+                AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh_kf4);
+        verifyValues(animator, 0, .2f, 1);
+    }
+
+    @UiThreadTest
+    public void testObjectAnimator() {
+        ObjectAnimator animator = (ObjectAnimator)
+                AnimatorInflater.loadAnimator(mActivity, R.animator.object_animator);
+        animator.setTarget(new DummyAnimatorTarget());
+        verifyValues(animator, "x", 0, 1);
+    }
+
+    @UiThreadTest
+    public void testObjectAnimatorPvh1() {
+        ObjectAnimator animator = (ObjectAnimator)
+                AnimatorInflater.loadAnimator(mActivity, R.animator.object_animator_pvh1);
+        animator.setTarget(new DummyAnimatorTarget());
+        verifyValues(animator, "x", 0, 1);
+        verifyValues(animator, "y", 10, 11);
+    }
+
+    @UiThreadTest
+    public void testObjectAnimatorPvhKf1() {
+        ObjectAnimator animator = (ObjectAnimator)
+                AnimatorInflater.loadAnimator(mActivity, R.animator.object_animator_pvh_kf1);
+        animator.setTarget(new DummyAnimatorTarget());
+        verifyValues(animator, "x", 0, 1);
+        verifyValues(animator, "y", 10, 11);
+    }
+
+    class DummyAnimatorTarget {
+        public float getX() {
+            return 0;
+        }
+
+        public void setX(float x) {
+        }
+
+        public float getY() {
+            return 0;
+        }
+
+        public void setY(float y) {
+        }
+    }
+
+    private void assertRoughlyEqual(float checkValue, float correctValue) {
+        // use epsilon for float compares
+        final float epsilon = .0001f;
+        assertTrue(checkValue > correctValue - epsilon && checkValue < correctValue + epsilon);
+    }
+
+    private void verifyValues(ValueAnimator animator, float... values) {
+        animator.setCurrentFraction(0);
+        assertRoughlyEqual((Float) animator.getAnimatedValue(), values[0]);
+        for (int i = 1; i < values.length - 1; ++i) {
+            animator.setCurrentFraction((float) i / (values.length - 1));
+            assertRoughlyEqual((Float) animator.getAnimatedValue(), values[i]);
+        }
+        animator.setCurrentFraction(1);
+        assertRoughlyEqual((Float) animator.getAnimatedValue(), values[values.length - 1]);
+    }
+
+    private void verifyValues(ObjectAnimator animator, String propertyName, float... values) {
+        animator.setCurrentFraction(0);
+        assertRoughlyEqual((Float) animator.getAnimatedValue(propertyName), values[0]);
+        for (int i = 1; i < values.length - 1; ++i) {
+            animator.setCurrentFraction((float) i / (values.length - 1));
+            assertRoughlyEqual((Float) animator.getAnimatedValue(propertyName), values[i]);
+        }
+        animator.setCurrentFraction(1);
+        assertRoughlyEqual((Float) animator.getAnimatedValue(propertyName),
+                values[values.length - 1]);
+    }
+}
diff --git a/tests/tests/animation/src/android/animation/cts/LayoutAnimationActivity.java b/tests/tests/animation/src/android/animation/cts/LayoutAnimationActivity.java
index 9b2eaff..fb5426e 100644
--- a/tests/tests/animation/src/android/animation/cts/LayoutAnimationActivity.java
+++ b/tests/tests/animation/src/android/animation/cts/LayoutAnimationActivity.java
@@ -15,7 +15,7 @@
  */
 package android.animation.cts;
 
-import com.android.cts.animation.R;
+import android.animation.cts.R;
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.View;
diff --git a/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java b/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java
index f9918a8..f39fe505 100644
--- a/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java
+++ b/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java
@@ -19,7 +19,7 @@
 import java.util.LinkedList;
 import java.util.List;
 
-import com.android.cts.animation.R;
+import android.animation.cts.R;
 
 import android.animation.Animator;
 import android.animation.LayoutTransition;
@@ -28,7 +28,6 @@
 import android.animation.PropertyValuesHolder;
 import android.animation.TimeInterpolator;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.TouchUtils;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AccelerateInterpolator;
@@ -41,6 +40,7 @@
     private MyLayoutTransition mLayoutTransition;
     private LinearLayout mView;
     private Button mButton;
+
     public LayoutAnimationTest() {
         super(LayoutAnimationActivity.class);
     }
@@ -65,14 +65,14 @@
         assertEquals(listener, actualListener);
     }
 
-    public void testIsRunning() {
+    public void testIsRunning() throws Throwable {
         setDefaultTransition();
         assertFalse(mLayoutTransition.isRunning());
-        TouchUtils.clickView(this, mButton);
+        clickButton();
         assertTrue(mLayoutTransition.isRunning());
     }
 
-    public void testIsChangingLayout() {
+    public void testIsChangingLayout() throws Throwable {
         long duration = 2000l;
         mView.setLayoutTransition(mLayoutTransition);
         mLayoutTransition.setDuration(duration);
@@ -80,7 +80,7 @@
                 new AccelerateInterpolator());
 
         assertFalse(mLayoutTransition.isChangingLayout());
-        TouchUtils.clickView(this, mButton);
+        clickButton();
         assertTrue(mLayoutTransition.isChangingLayout());
     }
 
@@ -138,7 +138,7 @@
         mLayoutTransition.setAnimator(LayoutTransition.APPEARING, appearingAnimator);
 
         List<Float> alphaList = new LinkedList<Float>();
-        TouchUtils.clickView(this, mButton);
+        clickButton();
         while(listener.mTransition) {
             float alpha = mActivity.getLastButton().getAlpha();
             alphaList.add(alpha);
@@ -177,6 +177,15 @@
                 new AccelerateInterpolator());
     }
 
+    private void clickButton() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mButton.callOnClick();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
+
     class MyTransitionListener implements LayoutTransition.TransitionListener {
         ViewGroup mContainer;
         View mView;
diff --git a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
index 5451472..7c85710 100644
--- a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
@@ -82,20 +82,138 @@
         assertEquals(startDelay, mValueAnimator.getStartDelay());
     }
 
-    public void testCurrentPlayTime() throws Throwable {
+    public void testGetCurrentPlayTime() throws Throwable {
         startAnimation(mValueAnimator);
         Thread.sleep(100);
         long currentPlayTime = mValueAnimator.getCurrentPlayTime();
         assertTrue(currentPlayTime  >  0);
     }
 
+    /**
+     * Test for equality within some epsilon. This accounts for minor differences
+     * due to floating-point accuracy.
+     */
+    private void assertRoughlyEqual(float expected, float actual) {
+        final float epsilon = .001f;
+        assertTrue(actual > (expected - epsilon) && actual < (expected + epsilon));
+    }
+
+    public void testSetCurrentPlayTime() throws Throwable {
+        final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
+        final ValueAnimator delayedAnim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
+        delayedAnim.setStartDelay(mDuration);
+        final long proposedCurrentPlayTime = mDuration / 2;
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.setCurrentPlayTime(mDuration / 2);
+                long currentPlayTime = anim.getCurrentPlayTime();
+                float currentFraction = anim.getAnimatedFraction();
+                float currentValue = (Float) anim.getAnimatedValue();
+                assertEquals(proposedCurrentPlayTime, currentPlayTime);
+                assertRoughlyEqual(.5f, currentFraction);
+                assertRoughlyEqual(50, currentValue);
+
+                delayedAnim.setCurrentPlayTime(mDuration / 2);
+                currentPlayTime = delayedAnim.getCurrentPlayTime();
+                currentFraction = delayedAnim.getAnimatedFraction();
+                currentValue = (Float) delayedAnim.getAnimatedValue();
+                assertEquals(proposedCurrentPlayTime, currentPlayTime);
+                assertRoughlyEqual(.5f, currentFraction);
+                assertRoughlyEqual(50, currentValue);
+            }
+        });
+        // Now make sure that it's still true a little later, to test that we're
+        // getting a result based on the seek time, not the wall clock time
+        Thread.sleep(100);
+        long currentPlayTime = anim.getCurrentPlayTime();
+        float currentFraction = anim.getAnimatedFraction();
+        float currentValue = (Float) anim.getAnimatedValue();
+        assertEquals(proposedCurrentPlayTime, currentPlayTime);
+        assertRoughlyEqual(.5f, currentFraction);
+        assertRoughlyEqual(50, currentValue);
+
+        currentPlayTime = delayedAnim.getCurrentPlayTime();
+        currentFraction = delayedAnim.getAnimatedFraction();
+        currentValue = (Float) delayedAnim.getAnimatedValue();
+        assertEquals(proposedCurrentPlayTime, currentPlayTime);
+        assertRoughlyEqual(.5f, currentFraction);
+        assertRoughlyEqual(50, currentValue);
+
+        // Finally, start() the delayed animation and check that the play time was
+        // not affected by playing during the delay
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delayedAnim.start();
+                long currentPlayTime = delayedAnim.getCurrentPlayTime();
+                float currentFraction = delayedAnim.getAnimatedFraction();
+                float currentValue = (Float) delayedAnim.getAnimatedValue();
+                assertEquals(proposedCurrentPlayTime, currentPlayTime);
+                assertRoughlyEqual(.5f, currentFraction);
+                assertRoughlyEqual(50, currentValue);
+            }
+        });
+
+        Thread.sleep(100);
+        currentPlayTime = delayedAnim.getCurrentPlayTime();
+        currentFraction = delayedAnim.getAnimatedFraction();
+        currentValue = (Float) delayedAnim.getAnimatedValue();
+        assertEquals(proposedCurrentPlayTime, currentPlayTime);
+        assertRoughlyEqual(.5f, currentFraction);
+        assertRoughlyEqual(50, currentValue);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delayedAnim.cancel();
+            }
+        });
+    }
+
+    public void testSetCurrentFraction() throws Throwable {
+        final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
+        final long proposedCurrentPlayTime = mDuration / 2;
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.setCurrentFraction(.5f);
+                long currentPlayTime = anim.getCurrentPlayTime();
+                float currentFraction = anim.getAnimatedFraction();
+                float currentValue = (Float) anim.getAnimatedValue();
+                assertEquals(proposedCurrentPlayTime, currentPlayTime);
+                assertRoughlyEqual(.5f, currentFraction);
+                assertRoughlyEqual(50, currentValue);
+            }
+        });
+        // Now make sure that it's still true a little later, to test that we're
+        // getting a result based on the seek time, not the wall clock time
+        Thread.sleep(100);
+        long currentPlayTime = anim.getCurrentPlayTime();
+        float currentFraction = anim.getAnimatedFraction();
+        float currentValue = (Float) anim.getAnimatedValue();
+        assertEquals(proposedCurrentPlayTime, currentPlayTime);
+        assertRoughlyEqual(.5f, currentFraction);
+        assertRoughlyEqual(50, currentValue);
+    }
+
     public void testGetFrameDelay() throws Throwable {
-        long frameDelay = 10;
-        mValueAnimator.setFrameDelay(frameDelay);
+        final long frameDelay = 10;
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mValueAnimator.setFrameDelay(frameDelay);
+            }
+        });
         startAnimation(mValueAnimator);
         Thread.sleep(100);
-        long actualFrameDelay = mValueAnimator.getFrameDelay();
-        assertEquals(frameDelay, actualFrameDelay);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                long actualFrameDelay = mValueAnimator.getFrameDelay();
+                assertEquals(frameDelay, actualFrameDelay);
+            }
+        });
     }
 
     public void testSetInterpolator() throws Throwable {
diff --git a/tests/tests/app.usage/Android.mk b/tests/tests/app.usage/Android.mk
index f245e5f..52118bc 100644
--- a/tests/tests/app.usage/Android.mk
+++ b/tests/tests/app.usage/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/app.usage/AndroidTest.xml b/tests/tests/app.usage/AndroidTest.xml
new file mode 100644
index 0000000..d4967f9
--- /dev/null
+++ b/tests/tests/app.usage/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for app.usage Tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsUsageStatsTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.app.usage.cts" />
+        <option name="runtime-hint" value="1m47s" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
deleted file mode 100644
index 301f931..0000000
--- a/tests/tests/app/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common voip-common org.apache.http.legacy
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ctstestserver
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-
-LOCAL_PACKAGE_NAME := CtsAppTestCases
-
-LOCAL_INSTRUMENTATION_FOR := CtsAppTestStubs
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/app/AndroidManifest.xml b/tests/tests/app/AndroidManifest.xml
deleted file mode 100644
index d05648c..0000000
--- a/tests/tests/app/AndroidManifest.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.app">
-
-    <uses-sdk android:minSdkVersion="11" />
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-    <uses-permission android:name="android.permission.BODY_SENSORS" />
-    <application>
-        <uses-library android:name="android.test.runner" />
-        <uses-library android:name="org.apache.http.legacy" android:required="false" />
-    </application>
-
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.app.stub"
-                     android:label="CTS tests of android.app">
-        <meta-data android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
-    </instrumentation>
-
-</manifest>
-
diff --git a/tests/tests/app/src/android/app/backup/cts/BackupManagerTest.java b/tests/tests/app/src/android/app/backup/cts/BackupManagerTest.java
deleted file mode 100644
index 1b0a401..0000000
--- a/tests/tests/app/src/android/app/backup/cts/BackupManagerTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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 android.app.backup.cts;
-
-import android.app.backup.BackupManager;
-import android.app.backup.RestoreObserver;
-import android.test.AndroidTestCase;
-
-public class BackupManagerTest extends AndroidTestCase {
-
-    public void testBackupManager() throws Exception {
-        // Check that these don't crash as if they were called in an app...
-        BackupManager backupManager = new BackupManager(mContext);
-        backupManager.dataChanged();
-        BackupManager.dataChanged("com.android.cts.app.stub");
-
-        // Backup isn't expected to work in this test but check for obvious bugs...
-        int result = backupManager.requestRestore(new RestoreObserver() {});
-        assertTrue(result != 0);
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/ActionBarTest.java b/tests/tests/app/src/android/app/cts/ActionBarTest.java
deleted file mode 100644
index 75e7807..0000000
--- a/tests/tests/app/src/android/app/cts/ActionBarTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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 android.app.cts;
-
-import android.app.ActionBar;
-import android.app.ActionBar.Tab;
-import android.app.ActionBar.TabListener;
-import android.app.FragmentTransaction;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-
-public class ActionBarTest extends ActivityInstrumentationTestCase2<ActionBarActivity> {
-
-    private ActionBarActivity mActivity;
-    private ActionBar mBar;
-
-    public ActionBarTest() {
-        super(ActionBarActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mBar = mActivity.getActionBar();
-    }
-
-    @UiThreadTest
-    public void testAddTab() {
-        if (mBar == null) {
-            return;
-        }
-        assertEquals(0, mBar.getTabCount());
-
-        Tab t1 = createTab("Tab 1");
-        mBar.addTab(t1);
-        assertEquals(1, mBar.getTabCount());
-        assertEquals(t1, mBar.getSelectedTab());
-        assertEquals(t1, mBar.getTabAt(0));
-
-        Tab t2 = createTab("Tab 2");
-        mBar.addTab(t2);
-        assertEquals(2, mBar.getTabCount());
-        assertEquals(t1, mBar.getSelectedTab());
-        assertEquals(t2, mBar.getTabAt(1));
-
-        Tab t3 = createTab("Tab 3");
-        mBar.addTab(t3, true);
-        assertEquals(3, mBar.getTabCount());
-        assertEquals(t3, mBar.getSelectedTab());
-        assertEquals(t3, mBar.getTabAt(2));
-
-        Tab t4 = createTab("Tab 2.5");
-        mBar.addTab(t4, 2);
-        assertEquals(4, mBar.getTabCount());
-        assertEquals(t4, mBar.getTabAt(2));
-        assertEquals(t3, mBar.getTabAt(3));
-
-        Tab t5 = createTab("Tab 0.5");
-        mBar.addTab(t5, 0, true);
-        assertEquals(5, mBar.getTabCount());
-        assertEquals(t5, mBar.getSelectedTab());
-        assertEquals(t5, mBar.getTabAt(0));
-        assertEquals(t1, mBar.getTabAt(1));
-        assertEquals(t2, mBar.getTabAt(2));
-        assertEquals(t4, mBar.getTabAt(3));
-        assertEquals(t3, mBar.getTabAt(4));
-    }
-
-    private Tab createTab(String name) {
-        return mBar.newTab().setText("Tab 1").setTabListener(new TestTabListener());
-    }
-
-    static class TestTabListener implements TabListener {
-        @Override
-        public void onTabSelected(Tab tab, FragmentTransaction ft) {
-        }
-
-        @Override
-        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
-        }
-
-        @Override
-        public void onTabReselected(Tab tab, FragmentTransaction ft) {
-        }
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/ActivityGroupTest.java b/tests/tests/app/src/android/app/cts/ActivityGroupTest.java
deleted file mode 100644
index f5fc0bd..0000000
--- a/tests/tests/app/src/android/app/cts/ActivityGroupTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-
-import android.app.ActivityGroup;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-
-public class ActivityGroupTest extends ActivityTestsBase {
-    private Intent mTabIntent;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTabIntent = new Intent(mContext, LaunchpadTabActivity.class);
-        mTabIntent.putExtra("tab", new ComponentName(mContext, LaunchpadActivity.class));
-    }
-
-    public void testTabBasic() throws Exception {
-        mIntent = mTabIntent;
-        runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC);
-    }
-
-    public void testTabScreen() throws Exception {
-        mIntent = mTabIntent;
-        runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN);
-    }
-
-    public void testTabDialog() throws Exception {
-        mIntent = mTabIntent;
-        runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG);
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java b/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
deleted file mode 100644
index 639741d..0000000
--- a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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 android.app.cts;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.WindowManager;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * {@link ActivityInstrumentationTestCase2} that tests {@link ActivityManager#getMemoryClass()}
- * by checking that the memory class matches the proper screen density and by launching an
- * application that attempts to allocate memory on the heap.
- */
-public class ActivityManagerMemoryClassTest
-        extends ActivityInstrumentationTestCase2<ActivityManagerMemoryClassLaunchActivity> {
-
-    public ActivityManagerMemoryClassTest() {
-        super(ActivityManagerMemoryClassLaunchActivity.class);
-    }
-
-    public static class ExpectedMemorySizesClass {
-        private static final Map<Integer, Integer> expectedMemorySizeForWatch
-            =  new HashMap<Integer, Integer>();
-        private static final Map<Integer, Integer> expectedMemorySizeForSmallNormalScreen
-            =  new HashMap<Integer, Integer>();
-        private static final Map<Integer, Integer> expectedMemorySizeForLargeScreen
-            =  new HashMap<Integer, Integer>();
-        private static final Map<Integer, Integer> expectedMemorySizeForXLargeScreen
-            =  new HashMap<Integer, Integer>();
-
-        static {
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_LOW, 32);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_MEDIUM, 32);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_TV, 32);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_HIGH, 36);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_280, 36);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XHIGH, 48);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_360, 48);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_400, 56);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_420, 64);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXHIGH, 88);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_560, 112);
-            expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXXHIGH, 154);
-        }
-
-        static {
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_LOW, 32);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_MEDIUM, 32);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_TV, 48);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_HIGH, 48);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_280, 48);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XHIGH, 80);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_360, 80);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_400, 96);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_420, 112);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXHIGH, 128);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_560, 192);
-            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 256);
-        }
-
-        static {
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_LOW, 32);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_MEDIUM, 64);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_TV, 80);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_HIGH, 80);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_280, 96);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XHIGH, 128);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_360, 160);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_400, 192);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_420, 228);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XXHIGH, 256);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_560, 384);
-            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 512);
-        }
-
-        static {
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_LOW, 48);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_MEDIUM, 80);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_TV, 96);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_HIGH, 96);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_280, 144);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XHIGH, 192);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_360, 240);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_400, 288);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_420, 336);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXHIGH, 384);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_560, 576);
-            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 768);
-        }
-
-        public static Integer getExpectedMemorySize(
-                int screenSize,
-                int screenDensity,
-                boolean isWatch) {
-
-           if (isWatch) {
-              return expectedMemorySizeForWatch.get(screenDensity);
-           }
-
-           switch (screenSize) {
-                case Configuration.SCREENLAYOUT_SIZE_SMALL:
-                case Configuration.SCREENLAYOUT_SIZE_NORMAL:
-                    return expectedMemorySizeForSmallNormalScreen.get(screenDensity);
-                case Configuration.SCREENLAYOUT_SIZE_LARGE:
-                    return expectedMemorySizeForLargeScreen.get(screenDensity);
-                case Configuration.SCREENLAYOUT_SIZE_XLARGE:
-                    return expectedMemorySizeForXLargeScreen.get(screenDensity);
-                default:
-                    throw new IllegalArgumentException("No memory requirement specified "
-                        + " for screen layout size " + screenSize);
-           }
-        }
-    }
-
-    public void testGetMemoryClass() throws Exception {
-        int memoryClass = getMemoryClass();
-        int screenDensity = getScreenDensity();
-        int screenSize = getScreenSize();
-        assertMemoryForScreenDensity(memoryClass, screenDensity, screenSize);
-
-        runHeapTestApp(memoryClass);
-    }
-
-    private int getMemoryClass() {
-        Context context = getInstrumentation().getTargetContext();
-        ActivityManager activityManager =
-                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-        return activityManager.getMemoryClass();
-    }
-
-    private int getScreenDensity() {
-        Context context = getInstrumentation().getTargetContext();
-        WindowManager windowManager =
-                (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        Display display = windowManager.getDefaultDisplay();
-        DisplayMetrics metrics = new DisplayMetrics();
-        display.getMetrics(metrics);
-        return metrics.densityDpi;
-    }
-
-    private int getScreenSize() {
-        Context context = getInstrumentation().getTargetContext();
-        Configuration config = context.getResources().getConfiguration();
-        return config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
-    }
-
-    private void assertMemoryForScreenDensity(int memoryClass, int screenDensity, int screenSize) {
-        Context context = getInstrumentation().getTargetContext();
-        boolean isWatch =
-            context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
-        int expectedMinimumMemory =
-            ExpectedMemorySizesClass.getExpectedMemorySize(screenSize, screenDensity, isWatch);
-
-        assertTrue("Expected to have at least " + expectedMinimumMemory
-                + "mb of memory for screen density " + screenDensity,
-                        memoryClass >= expectedMinimumMemory);
-    }
-
-    private void runHeapTestApp(int memoryClass) throws InterruptedException {
-        Intent intent = new Intent();
-        intent.putExtra(ActivityManagerMemoryClassLaunchActivity.MEMORY_CLASS_EXTRA,
-                memoryClass);
-        setActivityIntent(intent);
-        ActivityManagerMemoryClassLaunchActivity activity = getActivity();
-        assertEquals("The test application couldn't allocate memory close to the amount "
-                + " specified by the memory class.", Activity.RESULT_OK, activity.getResult());
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/tests/app/src/android/app/cts/ActivityManagerTest.java
deleted file mode 100644
index 02d13ef..0000000
--- a/tests/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.cts;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RecentTaskInfo;
-import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.ActivityManager.RunningServiceInfo;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityOptions;
-import android.app.Instrumentation;
-import android.app.Instrumentation.ActivityMonitor;
-import android.app.Instrumentation.ActivityResult;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ConfigurationInfo;
-import android.test.InstrumentationTestCase;
-
-public class ActivityManagerTest extends InstrumentationTestCase {
-    private static final String STUB_PACKAGE_NAME = "com.android.cts.app.stub";
-    private static final int WAITFOR_MSEC = 5000;
-    private static final String SERVICE_NAME = "android.app.cts.MockService";
-    private static final int WAIT_TIME = 2000;
-    // A secondary test activity from another APK.
-    private static final String SIMPLE_PACKAGE_NAME = "com.android.cts.launcherapps.simpleapp";
-    private static final String SIMPLE_ACTIVITY = ".SimpleActivity";
-    private static final String SIMPLE_ACTIVITY_IMMEDIATE_EXIT = ".SimpleActivityImmediateExit";
-    private static final String SIMPLE_ACTIVITY_CHAIN_EXIT = ".SimpleActivityChainExit";
-    // The action sent back by the SIMPLE_APP after a restart.
-    private static final String ACTIVITY_LAUNCHED_ACTION =
-            "com.android.cts.launchertests.LauncherAppsTests.LAUNCHED_ACTION";
-    // The action sent back by the SIMPLE_APP_IMMEDIATE_EXIT when it terminates.
-    private static final String ACTIVITY_EXIT_ACTION =
-            "com.android.cts.launchertests.LauncherAppsTests.EXIT_ACTION";
-    // The action sent back by the SIMPLE_APP_CHAIN_EXIT when the task chain ends. 
-    private static final String ACTIVITY_CHAIN_EXIT_ACTION =
-            "com.android.cts.launchertests.LauncherAppsTests.CHAIN_EXIT_ACTION";
-    // The action sent to identify the time track info.
-    private static final String ACTIVITY_TIME_TRACK_INFO = "com.android.cts.TIME_TRACK_INFO";
-    // Return states of the ActivityReceiverFilter.
-    public static final int RESULT_PASS = 1;
-    public static final int RESULT_FAIL = 2;
-    public static final int RESULT_TIMEOUT = 3;
-
-    private Context mContext;
-    private ActivityManager mActivityManager;
-    private Intent mIntent;
-    private List<Activity> mStartedActivityList;
-    private int mErrorProcessID;
-    private Instrumentation mInstrumentation;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mContext = mInstrumentation.getContext();
-        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
-        mStartedActivityList = new ArrayList<Activity>();
-        mErrorProcessID = -1;
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        if (mIntent != null) {
-            mInstrumentation.getContext().stopService(mIntent);
-        }
-        for (int i = 0; i < mStartedActivityList.size(); i++) {
-            mStartedActivityList.get(i).finish();
-        }
-        if (mErrorProcessID != -1) {
-            android.os.Process.killProcess(mErrorProcessID);
-        }
-    }
-
-    public void testGetRecentTasks() throws Exception {
-        int maxNum = 0;
-        int flags = 0;
-
-        List<RecentTaskInfo> recentTaskList;
-        // Test parameter: maxNum is set to 0
-        recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
-        assertNotNull(recentTaskList);
-        assertTrue(recentTaskList.size() == 0);
-        // Test parameter: maxNum is set to 50
-        maxNum = 50;
-        recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
-        assertNotNull(recentTaskList);
-        // start recent1_activity.
-        startSubActivity(ActivityManagerRecentOneActivity.class);
-        Thread.sleep(WAIT_TIME);
-        // start recent2_activity
-        startSubActivity(ActivityManagerRecentTwoActivity.class);
-        Thread.sleep(WAIT_TIME);
-        /*
-         * assert both recent1_activity and recent2_activity exist in the recent
-         * tasks list. Moreover,the index of the recent2_activity is smaller
-         * than the index of recent1_activity
-         */
-        recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
-        int indexRecentOne = -1;
-        int indexRecentTwo = -1;
-        int i = 0;
-        for (RecentTaskInfo rti : recentTaskList) {
-            if (rti.baseIntent.getComponent().getClassName().equals(
-                    ActivityManagerRecentOneActivity.class.getName())) {
-                indexRecentOne = i;
-            } else if (rti.baseIntent.getComponent().getClassName().equals(
-                    ActivityManagerRecentTwoActivity.class.getName())) {
-                indexRecentTwo = i;
-            }
-            i++;
-        }
-        assertTrue(indexRecentOne != -1 && indexRecentTwo != -1);
-        assertTrue(indexRecentTwo < indexRecentOne);
-
-        try {
-            mActivityManager.getRecentTasks(-1, 0);
-            fail("Should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected exception
-        }
-    }
-
-    public void testGetRecentTasksLimitedToCurrentAPK() throws Exception {
-        int maxNum = 0;
-        int flags = 0;
-
-        // Check the number of tasks at this time.
-        List<RecentTaskInfo>  recentTaskList;
-        recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
-        int numberOfEntriesFirstRun = recentTaskList.size();
-
-        // Start another activity from another APK.
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        ActivityReceiverFilter receiver = new ActivityReceiverFilter(ACTIVITY_LAUNCHED_ACTION);
-        mContext.startActivity(intent);
-
-        // Make sure the activity has really started.
-        assertEquals(RESULT_PASS, receiver.waitForActivity());
-        receiver.close();
-
-        // There shouldn't be any more tasks in this list at this time.
-        recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
-        int numberOfEntriesSecondRun = recentTaskList.size();
-        assertTrue(numberOfEntriesSecondRun == numberOfEntriesFirstRun);
-    }
-
-    // The receiver filter needs to be instantiated with the command to filter for before calling
-    // startActivity.
-    private class ActivityReceiverFilter extends BroadcastReceiver {
-        // The activity we want to filter for.
-        private String mActivityToFilter;
-        private int result = RESULT_TIMEOUT;
-        public long mTimeUsed = 0;
-        private static final int TIMEOUT_IN_MS = 1000;
-
-        // Create the filter with the intent to look for.
-        public ActivityReceiverFilter(String activityToFilter) {
-            mActivityToFilter = activityToFilter;
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(mActivityToFilter);
-            mInstrumentation.getTargetContext().registerReceiver(this, filter);
-        }
-
-        // Turn off the filter.
-        public void close() {
-            mInstrumentation.getTargetContext().unregisterReceiver(this);
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(mActivityToFilter)) {
-                synchronized(this) {
-                   result = RESULT_PASS;
-                   if (mActivityToFilter.equals(ACTIVITY_TIME_TRACK_INFO)) {
-                       mTimeUsed = intent.getExtras().getLong(
-                               ActivityOptions.EXTRA_USAGE_TIME_REPORT);
-                   }
-                   notifyAll();
-                }
-            }
-        }
-
-        public int waitForActivity() {
-            synchronized(this) {
-                try {
-                    wait(TIMEOUT_IN_MS);
-                } catch (InterruptedException e) {
-                }
-            }
-            return result;
-        }
-    }
-
-    private final <T extends Activity> void startSubActivity(Class<T> activityClass) {
-        final Instrumentation.ActivityResult result = new ActivityResult(0, new Intent());
-        final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), result, false);
-        mInstrumentation.addMonitor(monitor);
-        launchActivity(STUB_PACKAGE_NAME, activityClass, null);
-        mStartedActivityList.add(monitor.waitForActivity());
-    }
-
-    public void testGetRunningTasks() {
-        // Test illegal parameter
-        List<RunningTaskInfo> runningTaskList;
-        runningTaskList = mActivityManager.getRunningTasks(-1);
-        assertTrue(runningTaskList.size() == 0);
-
-        runningTaskList = mActivityManager.getRunningTasks(0);
-        assertTrue(runningTaskList.size() == 0);
-
-        runningTaskList = mActivityManager.getRunningTasks(20);
-        int taskSize = runningTaskList.size();
-        assertTrue(taskSize >= 0 && taskSize <= 20);
-
-        // start recent1_activity.
-        startSubActivity(ActivityManagerRecentOneActivity.class);
-        // start recent2_activity
-        startSubActivity(ActivityManagerRecentTwoActivity.class);
-
-        /*
-         * assert both recent1_activity and recent2_activity exist in the
-         * running tasks list. Moreover,the index of the recent2_activity is
-         * smaller than the index of recent1_activity
-         */
-        runningTaskList = mActivityManager.getRunningTasks(20);
-        int indexRecentOne = -1;
-        int indexRecentTwo = -1;
-        int i = 0;
-        for (RunningTaskInfo rti : runningTaskList) {
-            if (rti.baseActivity.getClassName().equals(
-                    ActivityManagerRecentOneActivity.class.getName())) {
-                indexRecentOne = i;
-            } else if (rti.baseActivity.getClassName().equals(
-                    ActivityManagerRecentTwoActivity.class.getName())) {
-                indexRecentTwo = i;
-            }
-            i++;
-        }
-        assertTrue(indexRecentOne != -1 && indexRecentTwo != -1);
-        assertTrue(indexRecentTwo < indexRecentOne);
-    }
-
-    public void testGetRunningServices() throws Exception {
-        // Test illegal parameter
-        List<RunningServiceInfo> runningServiceInfo;
-        runningServiceInfo = mActivityManager.getRunningServices(-1);
-        assertTrue(runningServiceInfo.size() == 0);
-
-        runningServiceInfo = mActivityManager.getRunningServices(0);
-        assertTrue(runningServiceInfo.size() == 0);
-
-        runningServiceInfo = mActivityManager.getRunningServices(5);
-        assertTrue(runningServiceInfo.size() >= 0 && runningServiceInfo.size() <= 5);
-
-        Intent intent = new Intent();
-        intent.setClass(mInstrumentation.getTargetContext(), MockService.class);
-        mInstrumentation.getTargetContext().startService(intent);
-        Thread.sleep(WAIT_TIME);
-
-        runningServiceInfo = mActivityManager.getRunningServices(Integer.MAX_VALUE);
-        boolean foundService = false;
-        for (RunningServiceInfo rs : runningServiceInfo) {
-            if (rs.service.getClassName().equals(SERVICE_NAME)) {
-                foundService = true;
-                break;
-            }
-        }
-        assertTrue(foundService);
-        mContext.stopService(intent);
-        Thread.sleep(WAIT_TIME);
-    }
-
-    public void testGetMemoryInfo() {
-        ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();
-        mActivityManager.getMemoryInfo(outInfo);
-        assertTrue(outInfo.lowMemory == (outInfo.availMem <= outInfo.threshold));
-    }
-
-    public void testGetRunningAppProcesses() throws Exception {
-        List<RunningAppProcessInfo> list = mActivityManager.getRunningAppProcesses();
-        assertNotNull(list);
-        final String SYSTEM_PROCESS = "system";
-        boolean hasSystemProcess = false;
-        // The package name is also the default name for the application process
-        final String TEST_PROCESS = STUB_PACKAGE_NAME;
-        boolean hasTestProcess = false;
-        for (RunningAppProcessInfo ra : list) {
-            if (ra.processName.equals(SYSTEM_PROCESS)) {
-                hasSystemProcess = true;
-            } else if (ra.processName.equals(TEST_PROCESS)) {
-                hasTestProcess = true;
-            }
-        }
-        // For security reasons the system process is not exposed.
-        assertTrue(!hasSystemProcess && hasTestProcess);
-
-        for (RunningAppProcessInfo ra : list) {
-            if (ra.processName.equals("com.android.cts.app.stub:remote")) {
-                fail("should be no process named com.android.cts.app.stub:remote");
-            }
-        }
-        // start a new process
-        mIntent = new Intent("android.app.REMOTESERVICE");
-        mIntent.setPackage("com.android.cts.app.stub");
-        mInstrumentation.getTargetContext().startService(mIntent);
-        Thread.sleep(WAITFOR_MSEC);
-
-        List<RunningAppProcessInfo> listNew = mActivityManager.getRunningAppProcesses();
-        assertTrue(list.size() <= listNew.size());
-
-        for (RunningAppProcessInfo ra : listNew) {
-            if (ra.processName.equals("com.android.cts.app.stub:remote")) {
-                return;
-            }
-        }
-        fail("com.android.cts.app.stub:remote process should be available");
-    }
-
-    public void testGetProcessInErrorState() throws Exception {
-        List<ActivityManager.ProcessErrorStateInfo> errList = null;
-        errList = mActivityManager.getProcessesInErrorState();
-    }
-
-    public void testRestartPackage() {
-    }
-
-    public void testGetDeviceConfigurationInfo() {
-        ConfigurationInfo conInf = mActivityManager.getDeviceConfigurationInfo();
-        assertNotNull(conInf);
-    }
-
-    /**
-     * Simple test for {@link ActivityManager.isUserAMonkey()} - verifies its false.
-     *
-     * TODO: test positive case
-     */
-    public void testIsUserAMonkey() {
-        assertFalse(ActivityManager.isUserAMonkey());
-    }
-
-    /**
-     * Verify that {@link ActivityManager.isRunningInTestHarness()} is false.
-     */
-    public void testIsRunningInTestHarness() {
-        assertFalse("isRunningInTestHarness must be false in production builds",
-                ActivityManager.isRunningInTestHarness());
-    }
-
-    /**
-     * Go back to the home screen since running applications can interfere with application
-     * lifetime tests.
-     */
-    private void launchHome() throws Exception {
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.addCategory(Intent.CATEGORY_HOME);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mContext.startActivity(intent);
-        Thread.sleep(WAIT_TIME);
-    }
-
-    /**
-     * Verify that the TimeTrackingAPI works properly when starting and ending an activity.
-     */
-    public void testTimeTrackingAPI_SimpleStartExit() throws Exception {
-        launchHome();
-        // Prepare to start an activity from another APK.
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setClassName(SIMPLE_PACKAGE_NAME,
-                SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY_IMMEDIATE_EXIT);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        // Prepare the time receiver action.
-        Context context = mInstrumentation.getTargetContext();
-        ActivityOptions options = ActivityOptions.makeBasic();
-        Intent receiveIntent = new Intent(ACTIVITY_TIME_TRACK_INFO);
-        options.requestUsageTimeReport(PendingIntent.getBroadcast(context,
-                0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT));
-
-        // The application finished tracker.
-        ActivityReceiverFilter appEndReceiver = new ActivityReceiverFilter(ACTIVITY_EXIT_ACTION);
-
-        // The filter for the time event.
-        ActivityReceiverFilter timeReceiver = new ActivityReceiverFilter(ACTIVITY_TIME_TRACK_INFO);
-
-        // Run the activity.
-        mContext.startActivity(intent, options.toBundle());
-
-        // Wait until it finishes and end the reciever then.
-        assertEquals(RESULT_PASS, appEndReceiver.waitForActivity());
-        appEndReceiver.close();
-
-        // At this time the timerReceiver should not fire, even though the activity has shut down,
-        // because we are back to the home screen.
-        assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
-        assertTrue(timeReceiver.mTimeUsed == 0);
-
-        // Issuing now another activity will trigger the timing information release.
-        final Intent dummyIntent = new Intent(context, MockApplicationActivity.class);
-        dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        final Activity activity = mInstrumentation.startActivitySync(dummyIntent);
-
-        // Wait until it finishes and end the reciever then.
-        assertEquals(RESULT_PASS, timeReceiver.waitForActivity());
-        timeReceiver.close();
-        assertTrue(timeReceiver.mTimeUsed != 0);
-    }
-
-    /**
-     * Verify that the TimeTrackingAPI works properly when switching away from the monitored task.
-     */
-    public void testTimeTrackingAPI_SwitchAwayTriggers() throws Exception {
-        launchHome();
-
-        // Prepare to start an activity from another APK.
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        // Prepare the time receiver action.
-        Context context = mInstrumentation.getTargetContext();
-        ActivityOptions options = ActivityOptions.makeBasic();
-        Intent receiveIntent = new Intent(ACTIVITY_TIME_TRACK_INFO);
-        options.requestUsageTimeReport(PendingIntent.getBroadcast(context,
-                0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT));
-
-        // The application started tracker.
-        ActivityReceiverFilter appStartedReceiver = new ActivityReceiverFilter(
-                ACTIVITY_LAUNCHED_ACTION);
-
-        // The filter for the time event.
-        ActivityReceiverFilter timeReceiver = new ActivityReceiverFilter(ACTIVITY_TIME_TRACK_INFO);
-
-        // Run the activity.
-        mContext.startActivity(intent, options.toBundle());
-
-        // Wait until it finishes and end the reciever then.
-        assertEquals(RESULT_PASS, appStartedReceiver.waitForActivity());
-        appStartedReceiver.close();
-
-        // At this time the timerReceiver should not fire since our app is running.
-        assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
-        assertTrue(timeReceiver.mTimeUsed == 0);
-
-        // Starting now another activity will put ours into the back hence releasing the timing.
-        final Intent dummyIntent = new Intent(context, MockApplicationActivity.class);
-        dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        final Activity activity = mInstrumentation.startActivitySync(dummyIntent);
-
-        // Wait until it finishes and end the reciever then.
-        assertEquals(RESULT_PASS, timeReceiver.waitForActivity());
-        timeReceiver.close();
-        assertTrue(timeReceiver.mTimeUsed != 0);
-    }
-
-    /**
-     * Verify that the TimeTrackingAPI works properly when handling an activity chain gets started
-     * and ended.
-     */
-    public void testTimeTrackingAPI_ChainedActivityExit() throws Exception {
-        launchHome();
-        // Prepare to start an activity from another APK.
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setClassName(SIMPLE_PACKAGE_NAME,
-                SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY_CHAIN_EXIT);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        // Prepare the time receiver action.
-        Context context = mInstrumentation.getTargetContext();
-        ActivityOptions options = ActivityOptions.makeBasic();
-        Intent receiveIntent = new Intent(ACTIVITY_TIME_TRACK_INFO);
-        options.requestUsageTimeReport(PendingIntent.getBroadcast(context,
-                0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT));
-
-        // The application finished tracker.
-        ActivityReceiverFilter appEndReceiver = new ActivityReceiverFilter(
-                ACTIVITY_CHAIN_EXIT_ACTION);
-
-        // The filter for the time event.
-        ActivityReceiverFilter timeReceiver = new ActivityReceiverFilter(ACTIVITY_TIME_TRACK_INFO);
-
-        // Run the activity.
-        mContext.startActivity(intent, options.toBundle());
-
-        // Wait until it finishes and end the reciever then.
-        assertEquals(RESULT_PASS, appEndReceiver.waitForActivity());
-        appEndReceiver.close();
-
-        // At this time the timerReceiver should not fire, even though the activity has shut down.
-        assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
-        assertTrue(timeReceiver.mTimeUsed == 0);
-
-        // Issue another activity so that the timing information gets released.
-        final Intent dummyIntent = new Intent(context, MockApplicationActivity.class);
-        dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        final Activity activity = mInstrumentation.startActivitySync(dummyIntent);
-
-        // Wait until it finishes and end the reciever then.
-        assertEquals(RESULT_PASS, timeReceiver.waitForActivity());
-        timeReceiver.close();
-        assertTrue(timeReceiver.mTimeUsed != 0);
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/ActivityManager_RunningServiceInfoTest.java b/tests/tests/app/src/android/app/cts/ActivityManager_RunningServiceInfoTest.java
deleted file mode 100644
index a6a38ae..0000000
--- a/tests/tests/app/src/android/app/cts/ActivityManager_RunningServiceInfoTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.cts;
-
-import android.app.ActivityManager;
-import android.content.ComponentName;
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-
-public class ActivityManager_RunningServiceInfoTest extends AndroidTestCase {
-    private ActivityManager.RunningServiceInfo mRunningServiceInfo;
-    private ComponentName mService;
-    private static final String PROCESS = "process";
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mRunningServiceInfo = new ActivityManager.RunningServiceInfo();
-        mService = new ComponentName(getContext(), MockActivity.class);
-
-        mRunningServiceInfo.service = mService;
-        mRunningServiceInfo.pid = 1;
-        mRunningServiceInfo.process = PROCESS;
-        mRunningServiceInfo.foreground = true;
-        mRunningServiceInfo.activeSince = 1l;
-        mRunningServiceInfo.started = true;
-        mRunningServiceInfo.clientCount = 2;
-        mRunningServiceInfo.crashCount = 1;
-        mRunningServiceInfo.lastActivityTime = 1l;
-        mRunningServiceInfo.restarting = 1l;
-    }
-
-    public void testConstructor() {
-        new ActivityManager.RunningServiceInfo();
-    }
-
-    public void testDescribeContents() {
-        assertEquals(0, mRunningServiceInfo.describeContents());
-    }
-
-    public void testWriteToParcel() throws Exception {
-
-        Parcel parcel = Parcel.obtain();
-        mRunningServiceInfo.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        ActivityManager.RunningServiceInfo values =
-            ActivityManager.RunningServiceInfo.CREATOR.createFromParcel(parcel);
-        assertEquals(mService, values.service);
-        assertEquals(1, values.pid);
-        assertEquals(PROCESS, values.process);
-        assertTrue(values.foreground);
-        assertEquals(1l, values.activeSince);
-        assertTrue(values.started);
-        assertEquals(2, values.clientCount);
-        assertEquals(1, values.crashCount);
-        assertEquals(1l, values.lastActivityTime);
-        assertEquals(1l, values.restarting);
-    }
-
-    public void testReadFromParcel() throws Exception {
-
-        Parcel parcel = Parcel.obtain();
-        mRunningServiceInfo.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        ActivityManager.RunningServiceInfo values =
-            new ActivityManager.RunningServiceInfo();
-        values.readFromParcel(parcel);
-        assertEquals(mService, values.service);
-        assertEquals(1, values.pid);
-        assertEquals(PROCESS, values.process);
-        assertTrue(values.foreground);
-        assertEquals(1l, values.activeSince);
-        assertTrue(values.started);
-        assertEquals(2, values.clientCount);
-        assertEquals(1, values.crashCount);
-        assertEquals(1l, values.lastActivityTime);
-        assertEquals(1l, values.restarting);
-    }
-
-}
diff --git a/tests/tests/app/src/android/app/cts/AlarmManagerTest.java b/tests/tests/app/src/android/app/cts/AlarmManagerTest.java
deleted file mode 100644
index b85c616..0000000
--- a/tests/tests/app/src/android/app/cts/AlarmManagerTest.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-
-import android.app.AlarmManager;
-import android.app.AlarmManager.AlarmClockInfo;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.cts.util.PollingCheck;
-import android.os.Build;
-import android.os.SystemClock;
-import android.test.AndroidTestCase;
-import android.util.Log;
-import android.test.MoreAsserts;
-
-public class AlarmManagerTest extends AndroidTestCase {
-    public static final String MOCKACTION = "android.app.AlarmManagerTest.TEST_ALARMRECEIVER";
-    public static final String MOCKACTION2 = "android.app.AlarmManagerTest.TEST_ALARMRECEIVER2";
-
-    private AlarmManager mAm;
-    private Intent mIntent;
-    private PendingIntent mSender;
-    private Intent mIntent2;
-    private PendingIntent mSender2;
-
-    /*
-     *  The default snooze delay: 5 seconds
-     */
-    private static final long SNOOZE_DELAY = 5 * 1000L;
-    private long mWakeupTime;
-    private MockAlarmReceiver mMockAlarmReceiver;
-    private MockAlarmReceiver mMockAlarmReceiver2;
-
-    private static final int TIME_DELTA = 1000;
-    private static final int TIME_DELAY = 10000;
-    private static final int REPEAT_PERIOD = 60000;
-
-    // Receiver registration/unregistration between tests races with the system process, so
-    // we add a little buffer time here to allow the system to process before we proceed.
-    // This value is in milliseconds.
-    private static final long REGISTER_PAUSE = 250;
-
-    // Constants used for validating exact vs inexact alarm batching immunity.  We run a few
-    // trials of an exact alarm that is placed within an inexact alarm's window of opportunity,
-    // and mandate that the average observed delivery skew between the two be statistically
-    // significant -- i.e. that the two alarms are not being coalesced.  We also place an
-    // additional exact alarm only a short time after the inexact alarm's nominal trigger time.
-    // If exact alarms are allowed to batch with inexact ones this will tend to have no effect,
-    // but in the correct behavior -- inexact alarms not permitted to batch with exact ones --
-    // this additional exact alarm will have the effect of guaranteeing that the inexact alarm
-    // must fire no later than it -- i.e. a considerable time before the significant, later
-    // exact alarm.
-    //
-    // The test essentially amounts to requiring that the inexact MOCKACTION alarm and
-    // the much later exact MOCKACTION2 alarm fire far apart, always; with an implicit
-    // insistence that alarm batches are delivered at the head of their window.
-    private static final long TEST_WINDOW_LENGTH = 5 * 1000L;
-    private static final long TEST_ALARM_FUTURITY = 6 * 1000L;
-    private static final long FAIL_DELTA = 50;
-    private static final long NUM_TRIALS = 5;
-    private static final long MAX_NEAR_DELIVERIES = 2;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mAm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-
-        mIntent = new Intent(MOCKACTION)
-                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        mSender = PendingIntent.getBroadcast(mContext, 0, mIntent, 0);
-        mMockAlarmReceiver = new MockAlarmReceiver(mIntent.getAction());
-
-        mIntent2 = new Intent(MOCKACTION2)
-                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        mSender2 = PendingIntent.getBroadcast(mContext, 0, mIntent2, 0);
-        mMockAlarmReceiver2 = new MockAlarmReceiver(mIntent2.getAction());
-
-        IntentFilter filter = new IntentFilter(mIntent.getAction());
-        mContext.registerReceiver(mMockAlarmReceiver, filter);
-
-        IntentFilter filter2 = new IntentFilter(mIntent2.getAction());
-        mContext.registerReceiver(mMockAlarmReceiver2, filter2);
-
-        Thread.sleep(REGISTER_PAUSE);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mContext.unregisterReceiver(mMockAlarmReceiver);
-        mContext.unregisterReceiver(mMockAlarmReceiver2);
-
-        Thread.sleep(REGISTER_PAUSE);
-    }
-
-    public void testSetTypes() throws Exception {
-        // TODO: try to find a way to make device sleep then test whether
-        // AlarmManager perform the expected way
-
-        // test parameter type is RTC_WAKEUP
-        mMockAlarmReceiver.setAlarmedFalse();
-        mWakeupTime = System.currentTimeMillis() + SNOOZE_DELAY;
-        mAm.setExact(AlarmManager.RTC_WAKEUP, mWakeupTime, mSender);
-        new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
-            @Override
-            protected boolean check() {
-                return mMockAlarmReceiver.alarmed;
-            }
-        }.run();
-        assertEquals(mMockAlarmReceiver.rtcTime, mWakeupTime, TIME_DELTA);
-
-        // test parameter type is RTC
-        mMockAlarmReceiver.setAlarmedFalse();
-        mWakeupTime = System.currentTimeMillis() + SNOOZE_DELAY;
-        mAm.setExact(AlarmManager.RTC, mWakeupTime, mSender);
-        new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
-            @Override
-            protected boolean check() {
-                return mMockAlarmReceiver.alarmed;
-            }
-        }.run();
-        assertEquals(mMockAlarmReceiver.rtcTime, mWakeupTime, TIME_DELTA);
-
-        // test parameter type is ELAPSED_REALTIME
-        mMockAlarmReceiver.setAlarmedFalse();
-        mWakeupTime = SystemClock.elapsedRealtime() + SNOOZE_DELAY;
-        mAm.setExact(AlarmManager.ELAPSED_REALTIME, mWakeupTime, mSender);
-        new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
-            @Override
-            protected boolean check() {
-                return mMockAlarmReceiver.alarmed;
-            }
-        }.run();
-        assertEquals(mMockAlarmReceiver.elapsedTime, mWakeupTime, TIME_DELTA);
-
-        // test parameter type is ELAPSED_REALTIME_WAKEUP
-        mMockAlarmReceiver.setAlarmedFalse();
-        mWakeupTime = SystemClock.elapsedRealtime() + SNOOZE_DELAY;
-        mAm.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, mWakeupTime, mSender);
-        new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
-            @Override
-            protected boolean check() {
-                return mMockAlarmReceiver.alarmed;
-            }
-        }.run();
-        assertEquals(mMockAlarmReceiver.elapsedTime, mWakeupTime, TIME_DELTA);
-    }
-
-    public void testAlarmTriggersImmediatelyIfSetTimeIsNegative() throws Exception {
-        // An alarm with a negative wakeup time should be triggered immediately.
-        // This exercises a workaround for a limitation of the /dev/alarm driver
-        // that would instead cause such alarms to never be triggered.
-        mMockAlarmReceiver.setAlarmedFalse();
-        mWakeupTime = -1000;
-        mAm.set(AlarmManager.RTC, mWakeupTime, mSender);
-        new PollingCheck(TIME_DELAY) {
-            @Override
-            protected boolean check() {
-                return mMockAlarmReceiver.alarmed;
-            }
-        }.run();
-    }
-
-    public void testExactAlarmBatching() throws Exception {
-        int deliveriesTogether = 0;
-        for (int i = 0; i < NUM_TRIALS; i++) {
-            final long now = System.currentTimeMillis();
-            final long windowStart = now + TEST_ALARM_FUTURITY;
-            final long exactStart = windowStart + TEST_WINDOW_LENGTH - 1;
-
-            mMockAlarmReceiver.setAlarmedFalse();
-            mMockAlarmReceiver2.setAlarmedFalse();
-            mAm.setWindow(AlarmManager.RTC_WAKEUP, windowStart, TEST_WINDOW_LENGTH, mSender);
-            mAm.setExact(AlarmManager.RTC_WAKEUP, exactStart, mSender2);
-
-            // Wait until a half-second beyond its target window, just to provide a
-            // little safety slop.
-            new PollingCheck(TEST_WINDOW_LENGTH + (windowStart - now) + 500) {
-                @Override
-                protected boolean check() {
-                    return mMockAlarmReceiver.alarmed;
-                }
-            }.run();
-
-            // Now wait until 1 sec beyond the expected exact alarm fire time, or for at
-            // least one second if we're already past the nominal exact alarm fire time
-            long timeToExact = Math.max(exactStart - System.currentTimeMillis() + 1000, 1000);
-            new PollingCheck(timeToExact) {
-                @Override
-                protected boolean check() {
-                    return mMockAlarmReceiver2.alarmed;
-                }
-            }.run();
-
-            // Success when we observe that the exact and windowed alarm are not being often
-            // delivered close together -- that is, when we can be confident that they are not
-            // being coalesced.
-            final long delta = Math.abs(mMockAlarmReceiver2.rtcTime - mMockAlarmReceiver.rtcTime);
-            Log.i("TEST", "[" + i + "]  delta = " + delta);
-            if (delta < FAIL_DELTA) {
-                deliveriesTogether++;
-                assertTrue("Exact alarms appear to be coalescing with inexact alarms",
-                        deliveriesTogether <= MAX_NEAR_DELIVERIES);
-            }
-        }
-    }
-
-    public void testSetRepeating() throws Exception {
-        mMockAlarmReceiver.setAlarmedFalse();
-        mWakeupTime = System.currentTimeMillis() + TEST_ALARM_FUTURITY;
-        mAm.setRepeating(AlarmManager.RTC_WAKEUP, mWakeupTime, REPEAT_PERIOD, mSender);
-
-        // wait beyond the initial alarm's possible delivery window to verify that it fires the first time
-        new PollingCheck(TEST_ALARM_FUTURITY + REPEAT_PERIOD) {
-            @Override
-            protected boolean check() {
-                return mMockAlarmReceiver.alarmed;
-            }
-        }.run();
-        assertTrue(mMockAlarmReceiver.alarmed);
-
-        // Now reset the receiver and wait for the intended repeat alarm to fire as expected
-        mMockAlarmReceiver.setAlarmedFalse();
-        new PollingCheck(REPEAT_PERIOD*2) {
-            @Override
-            protected boolean check() {
-                return mMockAlarmReceiver.alarmed;
-            }
-        }.run();
-        assertTrue(mMockAlarmReceiver.alarmed);
-
-        mAm.cancel(mSender);
-    }
-
-    public void testCancel() throws Exception {
-        mMockAlarmReceiver.setAlarmedFalse();
-        mMockAlarmReceiver2.setAlarmedFalse();
-
-        // set two alarms
-        final long when1 = System.currentTimeMillis() + TEST_ALARM_FUTURITY;
-        mAm.setExact(AlarmManager.RTC_WAKEUP, when1, mSender);
-        final long when2 = when1 + TIME_DELTA; // will fire after when1's target time
-        mAm.setExact(AlarmManager.RTC_WAKEUP, when2, mSender2);
-
-        // cancel the earlier one
-        mAm.cancel(mSender);
-
-        // and verify that only the later one fired
-        new PollingCheck(TIME_DELAY) {
-            @Override
-            protected boolean check() {
-                return mMockAlarmReceiver2.alarmed;
-            }
-        }.run();
-
-        assertFalse(mMockAlarmReceiver.alarmed);
-        assertTrue(mMockAlarmReceiver2.alarmed);
-    }
-
-    public void testSetInexactRepeating() throws Exception {
-        mAm.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
-                AlarmManager.INTERVAL_FIFTEEN_MINUTES, mSender);
-        SystemClock.setCurrentTimeMillis(System.currentTimeMillis()
-                + AlarmManager.INTERVAL_FIFTEEN_MINUTES);
-        // currently there is no way to write Android system clock. When try to
-        // write the system time, there will be log as
-        // " Unable to open alarm driver: Permission denied". But still fail
-        // after tried many permission.
-    }
-
-    public void testSetAlarmClock() throws Exception {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            mMockAlarmReceiver.setAlarmedFalse();
-            mMockAlarmReceiver2.setAlarmedFalse();
-
-            // Set first alarm clock.
-            final long wakeupTimeFirst = System.currentTimeMillis()
-                    + 2 * TEST_ALARM_FUTURITY;
-            mAm.setAlarmClock(new AlarmClockInfo(wakeupTimeFirst, null), mSender);
-
-            // Verify getNextAlarmClock returns first alarm clock.
-            AlarmClockInfo nextAlarmClock = mAm.getNextAlarmClock();
-            assertEquals(wakeupTimeFirst, nextAlarmClock.getTriggerTime());
-            assertNull(nextAlarmClock.getShowIntent());
-
-            // Set second alarm clock, earlier than first.
-            final long wakeupTimeSecond = System.currentTimeMillis()
-                    + TEST_ALARM_FUTURITY;
-            PendingIntent showIntentSecond = PendingIntent.getBroadcast(getContext(), 0,
-                    new Intent(getContext(), AlarmManagerTest.class).setAction("SHOW_INTENT"), 0);
-            mAm.setAlarmClock(new AlarmClockInfo(wakeupTimeSecond, showIntentSecond),
-                    mSender2);
-
-            // Verify getNextAlarmClock returns second alarm clock now.
-            nextAlarmClock = mAm.getNextAlarmClock();
-            assertEquals(wakeupTimeSecond, nextAlarmClock.getTriggerTime());
-            assertEquals(showIntentSecond, nextAlarmClock.getShowIntent());
-
-            // Cancel second alarm.
-            mAm.cancel(mSender2);
-
-            // Verify getNextAlarmClock returns first alarm clock again.
-            nextAlarmClock = mAm.getNextAlarmClock();
-            assertEquals(wakeupTimeFirst, nextAlarmClock.getTriggerTime());
-            assertNull(nextAlarmClock.getShowIntent());
-
-            // Wait for first alarm to trigger.
-            assertFalse(mMockAlarmReceiver.alarmed);
-            new PollingCheck(2 * TEST_ALARM_FUTURITY + TIME_DELAY) {
-                @Override
-                protected boolean check() {
-                    return mMockAlarmReceiver.alarmed;
-                }
-            }.run();
-
-            // Verify first alarm fired at the right time.
-            assertEquals(mMockAlarmReceiver.rtcTime, wakeupTimeFirst, TIME_DELTA);
-
-            // Verify second alarm didn't fire.
-            assertFalse(mMockAlarmReceiver2.alarmed);
-
-            // Verify the next alarm is not returning neither the first nor the second alarm.
-            nextAlarmClock = mAm.getNextAlarmClock();
-            MoreAsserts.assertNotEqual(wakeupTimeFirst, nextAlarmClock != null
-                    ? nextAlarmClock.getTriggerTime()
-                    : null);
-            MoreAsserts.assertNotEqual(wakeupTimeSecond, nextAlarmClock != null
-                    ? nextAlarmClock.getTriggerTime()
-                    : null);
-        }
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/AlertDialogTest.java b/tests/tests/app/src/android/app/cts/AlertDialogTest.java
deleted file mode 100644
index 3e9f3b2..0000000
--- a/tests/tests/app/src/android/app/cts/AlertDialogTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-
-import android.app.AlertDialog;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.DialogInterface.OnClickListener;
-import android.cts.util.PollingCheck;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Message;
-import android.test.ActivityInstrumentationTestCase2;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.Button;
-
-/*
- * Test AlertDialog
- */
-public class AlertDialogTest extends ActivityInstrumentationTestCase2<DialogStubActivity> {
-    private static final String ALERTDIALOG_CUSTOM_TITLE = "Hello, World!";
-
-    private Instrumentation mInstrumentation;
-    private DialogStubActivity mActivity;
-    private Button mPositiveButton;
-    private Button mNegativeButton;
-    private Button mNeutralButton;
-
-    public AlertDialogTest() {
-        super("com.android.cts.app.stub", DialogStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-    }
-
-    protected void startDialogActivity(int dialogNumber) {
-        mActivity = DialogStubActivity.startDialogActivity(this, dialogNumber);
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mActivity.getDialog().isShowing();
-            }
-        }.run();
-    }
-
-    public void testAlertDialog() throws Throwable {
-        doTestAlertDialog(DialogStubActivity.TEST_ALERTDIALOG);
-    }
-
-    private void doTestAlertDialog(int index) throws Throwable {
-        startDialogActivity(index);
-        assertTrue(mActivity.getDialog().isShowing());
-
-        mPositiveButton = ((AlertDialog) (mActivity.getDialog())).getButton(
-                DialogInterface.BUTTON_POSITIVE);
-        assertNotNull(mPositiveButton);
-        assertEquals(mActivity.getString(com.android.cts.app.stub.R.string.alert_dialog_positive),
-                mPositiveButton.getText());
-        mNeutralButton = ((AlertDialog) (mActivity.getDialog())).getButton(
-                DialogInterface.BUTTON_NEUTRAL);
-        assertNotNull(mNeutralButton);
-        assertEquals(mActivity.getString(com.android.cts.app.stub.R.string.alert_dialog_neutral),
-                mNeutralButton.getText());
-        mNegativeButton = ((AlertDialog) (mActivity.getDialog())).getButton(
-                DialogInterface.BUTTON_NEGATIVE);
-        assertNotNull(mNegativeButton);
-        assertEquals(mActivity.getString(com.android.cts.app.stub.R.string.alert_dialog_negative),
-                mNegativeButton.getText());
-
-        assertFalse(mActivity.isPositiveButtonClicked);
-        performClick(mPositiveButton);
-        assertTrue(mActivity.isPositiveButtonClicked);
-
-        assertFalse(mActivity.isNegativeButtonClicked);
-        performClick(mNegativeButton);
-        assertTrue(mActivity.isNegativeButtonClicked);
-
-        assertFalse(mActivity.isNeutralButtonClicked);
-        performClick(mNeutralButton);
-        assertTrue(mActivity.isNeutralButtonClicked);
-    }
-
-    public void testAlertDialogDeprecatedAPI() throws Throwable {
-        doTestAlertDialog(DialogStubActivity.TEST_ALERTDIALOG_DEPRECATED);
-    }
-
-    public void testAlertDialogDeprecatedAPIWithMessage() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ALERTDIALOG_DEPRECATED_WITH_MESSAGE);
-        assertTrue(mActivity.getDialog().isShowing());
-
-        mPositiveButton = ((AlertDialog) (mActivity.getDialog())).getButton(
-                DialogInterface.BUTTON_POSITIVE);
-        assertNotNull(mPositiveButton);
-        assertEquals(mActivity.getString(com.android.cts.app.stub.R.string.alert_dialog_positive),
-                mPositiveButton.getText());
-        mNegativeButton = ((AlertDialog) (mActivity.getDialog())).getButton(
-                DialogInterface.BUTTON_NEGATIVE);
-        assertNotNull(mNegativeButton);
-        assertEquals(mActivity.getString(com.android.cts.app.stub.R.string.alert_dialog_negative),
-                mNegativeButton.getText());
-        mNeutralButton = ((AlertDialog) (mActivity.getDialog())).getButton(
-                DialogInterface.BUTTON_NEUTRAL);
-        assertNotNull(mNeutralButton);
-        assertEquals(mActivity.getString(com.android.cts.app.stub.R.string.alert_dialog_neutral),
-                mNeutralButton.getText());
-
-        DialogStubActivity.buttonIndex = 0;
-        performClick(mPositiveButton);
-        assertEquals(DialogInterface.BUTTON_POSITIVE, DialogStubActivity.buttonIndex);
-
-        DialogStubActivity.buttonIndex = 0;
-        performClick(mNeutralButton);
-        assertEquals(DialogInterface.BUTTON_NEUTRAL, DialogStubActivity.buttonIndex);
-
-        DialogStubActivity.buttonIndex = 0;
-        performClick(mNegativeButton);
-        assertEquals(DialogInterface.BUTTON_NEGATIVE, DialogStubActivity.buttonIndex);
-    }
-
-    private void performClick(final Button button) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                button.performClick();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testCustomAlertDialog() {
-        startDialogActivity(DialogStubActivity.TEST_CUSTOM_ALERTDIALOG);
-        assertTrue(mActivity.getDialog().isShowing());
-    }
-
-    public void testCustomAlertDialogView() {
-        startDialogActivity(DialogStubActivity.TEST_CUSTOM_ALERTDIALOG_VIEW);
-        assertTrue(mActivity.getDialog().isShowing());
-    }
-
-
-    public void testCallback() {
-        startDialogActivity(DialogStubActivity.TEST_ALERTDIALOG_CALLBACK);
-        assertTrue(mActivity.onCreateCalled);
-
-        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
-        assertTrue(mActivity.onKeyDownCalled);
-        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
-        assertTrue(mActivity.onKeyUpCalled);
-    }
-
-    public void testAlertDialogTheme() throws Exception {
-        startDialogActivity(DialogStubActivity.TEST_ALERTDIALOG_THEME);
-        assertTrue(mActivity.getDialog().isShowing());
-    }
-
-    public void testAlertDialogCancelable() throws Exception {
-        startDialogActivity(DialogStubActivity.TEST_ALERTDIALOG_CANCELABLE);
-        assertTrue(mActivity.getDialog().isShowing());
-        assertFalse(mActivity.onCancelCalled);
-        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.onCancelCalled);
-    }
-
-    public void testAlertDialogNotCancelable() throws Exception {
-        startDialogActivity(DialogStubActivity.TEST_ALERTDIALOG_NOT_CANCELABLE);
-        assertTrue(mActivity.getDialog().isShowing());
-        assertFalse(mActivity.onCancelCalled);
-        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
-        assertFalse(mActivity.onCancelCalled);
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java b/tests/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
deleted file mode 100644
index 58e69b8..0000000
--- a/tests/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import java.util.ArrayList;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Instrumentation;
-import android.app.AlertDialog.Builder;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.DialogInterface.OnClickListener;
-import android.content.DialogInterface.OnKeyListener;
-import android.content.DialogInterface.OnMultiChoiceClickListener;
-import android.cts.util.PollingCheck;
-import android.database.Cursor;
-import android.database.CursorWrapper;
-import android.graphics.drawable.Drawable;
-import android.provider.Contacts.People;
-import android.test.ActivityInstrumentationTestCase2;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.AdapterView.OnItemSelectedListener;
-
-
-public class AlertDialog_BuilderTest extends ActivityInstrumentationTestCase2<DialogStubActivity> {
-    private Builder mBuilder;
-    private Context mContext;
-    private Instrumentation mInstrumentation;
-    private final CharSequence mTitle = "title";
-    private Drawable mDrawable;
-    private AlertDialog mDialog;
-    private Button mButton;
-    private boolean mResult;
-    private boolean mItemSelected;
-    private CharSequence mSelectedItem;
-    private final String[] mPROJECTION = new String[] {
-            People._ID, People.NAME
-    };
-
-    private View mView;
-    private ListView mListView;
-    private ArrayList<Integer> mSelectedItems;
-    private FrameLayout mFrameLayout;
-
-    private OnClickListener mOnClickListener = new OnClickListener() {
-        public void onClick(DialogInterface dialog, int which) {
-            mResult = true;
-        }
-    };
-
-    private OnCancelListener mOnCancelListener = new OnCancelListener() {
-        public void onCancel(DialogInterface dialog) {
-            mResult = true;
-        }
-    };
-
-    private OnKeyListener mOnKeyListener = new OnKeyListener() {
-        public boolean onKey(DialogInterface dialog, int key, KeyEvent envnt) {
-            mResult = true;
-            return true;
-        }
-    };
-
-    private OnItemSelectedListener mOnItemSelectedListener = new OnItemSelectedListener() {
-        public void onItemSelected(AdapterView parent, View v, int position, long id) {
-            mItemSelected = true;
-        }
-
-        public void onNothingSelected(AdapterView parent) {
-        }
-
-    };
-
-    private OnMultiChoiceClickListener mOnMultiChoiceClickListener =
-        new OnMultiChoiceClickListener() {
-        public void onClick(DialogInterface dialog, int which, boolean isChecked) {
-            mSelectedItems.add(which);
-            mResult = true;
-        }
-    };
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mBuilder = null;
-        mInstrumentation = getInstrumentation();
-        mContext = getActivity();
-        final Activity activity = getActivity();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return activity.hasWindowFocus();
-            }
-        }.run();
-        mButton = null;
-        mView = null;
-        mListView = null;
-        mDialog = null;
-        mItemSelected = false;
-        mSelectedItem = null;
-        mSelectedItems = new ArrayList<Integer>();
-    }
-
-    public AlertDialog_BuilderTest() {
-        super("com.android.cts.app.stub", DialogStubActivity.class);
-    }
-
-    public void testConstructor() {
-        new AlertDialog.Builder(mContext);
-    }
-
-    public void testSetIconWithParamInt() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mDrawable = mContext.getResources().getDrawable(android.R.drawable.btn_default);
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setIcon(android.R.drawable.btn_default);
-                mDialog = mBuilder.show();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testSetIconWithParamDrawable() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mDrawable = mContext.getResources().getDrawable(android.R.drawable.btn_default);
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setIcon(mDrawable);
-                mDialog = mBuilder.show();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testSetPositiveButtonWithParamInt() throws Throwable {
-       runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setPositiveButton(android.R.string.yes, mOnClickListener);
-                mDialog = mBuilder.show();
-                mButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
-                mButton.performClick();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertEquals(mContext.getText(android.R.string.yes), mButton.getText());
-        assertTrue(mResult);
-    }
-
-    public void testSetPositiveButtonWithParamCharSequence() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setPositiveButton(android.R.string.yes, mOnClickListener);
-                mDialog = mBuilder.show();
-                mButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
-                mButton.performClick();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(mContext.getText(android.R.string.yes), mButton.getText());
-        assertTrue(mResult);
-    }
-
-    public void testSetNegativeButtonWithParamCharSequence() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setNegativeButton(mTitle, mOnClickListener);
-                mDialog = mBuilder.show();
-                mButton = mDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
-                mButton.performClick();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(mTitle, mButton.getText());
-        assertTrue(mResult);
-    }
-
-    public void testSetNegativeButtonWithParamInt() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setNegativeButton(com.android.cts.app.stub.R.string.notify, mOnClickListener);
-                mDialog = mBuilder.show();
-                mButton = mDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
-                mButton.performClick();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(mContext.getText(com.android.cts.app.stub.R.string.notify), mButton.getText());
-        assertTrue(mResult);
-    }
-
-    public void testSetNeutralButtonWithParamInt() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setNeutralButton(com.android.cts.app.stub.R.string.notify, mOnClickListener);
-                mDialog = mBuilder.show();
-                mButton = mDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
-                mButton.performClick();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(mContext.getText(com.android.cts.app.stub.R.string.notify), mButton.getText());
-        assertTrue(mResult);
-    }
-
-    public void testSetNeutralButtonWithParamCharSequence() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setNeutralButton(mTitle, mOnClickListener);
-                mDialog = mBuilder.show();
-                mButton = mDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
-                mButton.performClick();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(mTitle, mButton.getText());
-        assertTrue(mResult);
-    }
-
-    private void testCancelable(final boolean cancelable) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setCancelable(cancelable);
-                mDialog = mBuilder.show();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mDialog.isShowing();
-            }
-        }.run();
-        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
-        mInstrumentation.waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                boolean showing = mDialog.isShowing();
-                if (cancelable) {
-                    // if the dialog is cancelable, then pressing back
-                    // should cancel it. Thus it should not be showing
-                    return !showing;
-                } else {
-                    // if the dialog is not cancelable, pressing back
-                    // should so nothing and it should still be showing
-                    return showing;
-                }
-            }
-        }.run();
-    }
-
-    public void testSetCancelable() throws Throwable {
-        testCancelable(true);
-    }
-
-    public void testDisableCancelable() throws Throwable {
-        testCancelable(false);
-    }
-
-    public void testSetOnCancelListener() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setOnCancelListener(mOnCancelListener);
-                mDialog = mBuilder.show();
-                mDialog.cancel();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mResult);
-    }
-
-    public void testSetOnKeyListener() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setOnKeyListener(mOnKeyListener);
-                mDialog = mBuilder.show();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        sendKeys(KeyEvent.ACTION_DOWN, KeyEvent.ACTION_DOWN);
-        assertTrue(mResult);
-    }
-
-    public void testSetItemsWithParamInt() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setItems(com.android.cts.app.stub.R.array.difficultyLevel, mOnClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        final CharSequence[] levels = mContext.getResources().getTextArray(
-                com.android.cts.app.stub.R.array.difficultyLevel);
-        assertEquals(levels[0], mListView.getItemAtPosition(0));
-    }
-
-    public void testSetItemsWithParamCharSequence() throws Throwable {
-        final CharSequence[] expect = mContext.getResources().getTextArray(
-                com.android.cts.app.stub.R.array.difficultyLevel);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setItems(expect, mOnClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(expect[0], mListView.getItemAtPosition(0));
-    }
-
-    public void testSetAdapter() throws Throwable {
-        final ListAdapter adapter = new AdapterTest();
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setAdapter(adapter, mOnClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(adapter, mListView.getAdapter());
-    }
-
-    public void testSetCursor() throws Throwable {
-        preparePeople();
-        final Cursor c = mContext.getContentResolver().query(People.CONTENT_URI, mPROJECTION, null,
-                null, null);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setCursor(c, mOnClickListener, People.NAME);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-                mListView.performItemClick(null, 0, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        final CursorWrapper selected = (CursorWrapper)mListView.getSelectedItem();
-        assertEquals(c.getString(1), selected.getString(1));
-        assertTrue(mResult);
-    }
-
-    public void testSetMultiChoiceItemsWithParamInt() throws Throwable {
-
-        final CharSequence[] items = mContext.getResources().getTextArray(
-                com.android.cts.app.stub.R.array.difficultyLevel);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setMultiChoiceItems(com.android.cts.app.stub.R.array.difficultyLevel, null,
-                        mOnMultiChoiceClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-                mSelectedItem = (CharSequence)mListView.getSelectedItem();
-                mListView.performItemClick(null, 0, 0);
-                mListView.performItemClick(null, 1, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(items[0], mSelectedItem);
-        assertEquals(2, mSelectedItems.size());
-        assertEquals(items[0], mListView.getItemAtPosition(0));
-        assertTrue(mResult);
-    }
-
-    public void testSetMultiChoiceItemsWithParamCharSequence() throws Throwable {
-        final CharSequence[] items = mContext.getResources().getTextArray(
-                com.android.cts.app.stub.R.array.difficultyLevel);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setMultiChoiceItems(items, null, mOnMultiChoiceClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-                mSelectedItem = (CharSequence)mListView.getSelectedItem();
-                mListView.performItemClick(null, 0, 0);
-                mListView.performItemClick(null, 1, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(items[0], mSelectedItem);
-        assertEquals(2, mSelectedItems.size());
-        assertEquals(items[0], mListView.getItemAtPosition(0));
-        assertTrue(mResult);
-    }
-
-    public void testSetMultiChoiceItemsWithParamCursor() throws Throwable {
-        preparePeople();
-        final Cursor c = mContext.getContentResolver().query(People.CONTENT_URI, mPROJECTION, null,
-                null, null);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setMultiChoiceItems(c, People.NAME, People.NAME,
-                        mOnMultiChoiceClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-                mListView.performItemClick(null, 0, 0);
-                mListView.performItemClick(null, 1, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        final CursorWrapper selected = (CursorWrapper)mListView.getSelectedItem();
-        assertEquals(c.getString(1), selected.getString(1));
-        assertEquals(2, mSelectedItems.size());
-        assertTrue(mResult);
-    }
-
-    public void testSetSingleChoiceItemsWithParamInt() throws Throwable {
-        final CharSequence[] items = mContext.getResources().getTextArray(
-                com.android.cts.app.stub.R.array.difficultyLevel);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setSingleChoiceItems(com.android.cts.app.stub.R.array.difficultyLevel, 0,
-                        mOnClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-                mSelectedItem = (CharSequence)mListView.getSelectedItem();
-                mListView.performItemClick(null, 0, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(items[0], mSelectedItem);
-        assertEquals(items[0], mListView.getItemAtPosition(0));
-        assertTrue(mResult);
-    }
-
-    private void preparePeople() {
-        final ContentResolver mResolver = mContext.getContentResolver();
-        mResolver.delete(People.CONTENT_URI, null, null);
-        final ContentValues valuse = new ContentValues();
-        valuse.put(People._ID, "1");
-        valuse.put(People.NAME, "name");
-        mResolver.insert(People.CONTENT_URI, valuse);
-    }
-
-    public void testSetSingleChoiceItemsWithParamCursor() throws Throwable {
-        final String[] PROJECTION = new String[] {
-                People._ID, People.NAME
-        };
-        preparePeople();
-        final Cursor c = mContext.getContentResolver().query(People.CONTENT_URI, PROJECTION, null,
-                null, null);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setSingleChoiceItems(c, 0, People.NAME, mOnClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-                mListView.performItemClick(null, 0, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        final CursorWrapper selected = (CursorWrapper)mListView.getSelectedItem();
-        assertEquals(c.getString(1), selected.getString(1));
-        assertTrue(mResult);
-    }
-
-    public void testSetSingleChoiceItemsWithParamCharSequence() throws Throwable {
-        final CharSequence[] items = mContext.getResources().getTextArray(
-                com.android.cts.app.stub.R.array.difficultyLevel);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setSingleChoiceItems(items, 0, mOnClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-                mSelectedItem = (CharSequence)mListView.getSelectedItem();
-                mListView.performItemClick(null, 0, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(items[0], mSelectedItem);
-        assertEquals(items[0], mListView.getItemAtPosition(0));
-        assertTrue(mResult);
-    }
-
-    public void testSetSingleChoiceItems() throws Throwable {
-        final CharSequence[] items = mContext.getResources().getTextArray(
-                com.android.cts.app.stub.R.array.difficultyLevel);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setSingleChoiceItems(new ArrayAdapter<CharSequence>(mContext,
-                        android.R.layout.select_dialog_singlechoice, android.R.id.text1, items), 0,
-                        mOnClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-                mSelectedItem = (CharSequence)mListView.getSelectedItem();
-                mListView.performItemClick(null, 0, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(items[0], mSelectedItem);
-        assertEquals(items[0], mListView.getItemAtPosition(0));
-        assertTrue(mResult);
-    }
-
-    public void testSetOnItemSelectedListener() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setOnItemSelectedListener(mOnItemSelectedListener);
-                mBuilder.setItems(com.android.cts.app.stub.R.array.difficultyLevel, mOnClickListener);
-                mDialog = mBuilder.show();
-                mListView = mDialog.getListView();
-                mListView.pointToPosition(0, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mItemSelected);
-    }
-
-    public void testSetView() throws Throwable {
-        final View view = new View(mContext);
-        view.setId(100);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setView(view);
-                mDialog = mBuilder.show();
-                mView = mDialog.getWindow().findViewById(100);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(view, mView);
-    }
-
-    public void testSetInverseBackgroundForced() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setInverseBackgroundForced(true);
-                mDialog = mBuilder.create();
-                mDialog.show();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testCreate() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mDialog = mBuilder.create();
-                mDialog.show();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertNotNull(mDialog);
-        assertTrue(mDialog.isShowing());
-    }
-
-    public void testShow() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mDialog = mBuilder.show();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mDialog.isShowing());
-    }
-
-    private static class AdapterTest implements android.widget.ListAdapter {
-        public boolean areAllItemsEnabled() {
-            return true;
-        }
-
-        public boolean isEnabled(int position) {
-            return false;
-        }
-
-        public int getCount() {
-            return 0;
-        }
-
-        public Object getItem(int position) {
-            return null;
-        }
-
-        public long getItemId(int position) {
-            return 0;
-        }
-
-        public int getItemViewType(int position) {
-            return 0;
-        }
-
-        public android.view.View getView( int position,
-                                          android.view.View convertView,
-                                          android.view.ViewGroup parent){
-            return null;
-        }
-
-        public int getViewTypeCount() {
-            return 1;
-        }
-
-        public boolean hasStableIds() {
-            return false;
-        }
-
-        public boolean isEmpty() {
-            return true;
-        }
-
-        public void registerDataSetObserver(
-            android.database.DataSetObserver observer) {
-        }
-
-        public void unregisterDataSetObserver(
-            android.database.DataSetObserver observer) {
-        }
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/AliasActivityTest.java b/tests/tests/app/src/android/app/cts/AliasActivityTest.java
deleted file mode 100644
index d44050f..0000000
--- a/tests/tests/app/src/android/app/cts/AliasActivityTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.AliasActivity;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.test.InstrumentationTestCase;
-
-public class AliasActivityTest extends InstrumentationTestCase {
-
-    private static final long SLEEP_TIME = 1000;
-
-    public void testAliasActivity() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                new AliasActivity();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        Context context = getInstrumentation().getTargetContext();
-
-        Intent intent = new Intent();
-        intent.setClass(context, AliasActivityStub.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        assertFalse(ChildActivity.isStarted);
-        assertFalse(AliasActivityStub.isOnCreateCalled);
-        context.startActivity(intent);
-        Thread.sleep(SLEEP_TIME);
-        assertTrue(AliasActivityStub.isOnCreateCalled);
-        assertTrue(ChildActivity.isStarted);
-        assertTrue(AliasActivityStub.isFinished);
-    }
-
-}
diff --git a/tests/tests/app/src/android/app/cts/ApplicationTest.java b/tests/tests/app/src/android/app/cts/ApplicationTest.java
deleted file mode 100644
index 99cc8ba..0000000
--- a/tests/tests/app/src/android/app/cts/ApplicationTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-
-import android.app.Activity;
-import android.app.Application;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.test.InstrumentationTestCase;
-
-/**
- * Test {@link Application}.
- */
-public class ApplicationTest extends InstrumentationTestCase {
-
-    public void testApplication() throws Throwable {
-        final Instrumentation instrumentation = getInstrumentation();
-        final Context targetContext = instrumentation.getTargetContext();
-
-        final Intent intent = new Intent(targetContext, MockApplicationActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        final Activity activity = instrumentation.startActivitySync(intent);
-        final MockApplication mockApp = (MockApplication) activity.getApplication();
-        assertTrue(mockApp.isConstructorCalled);
-        assertTrue(mockApp.isOnCreateCalled);
-
-        //skip if the device doesn't support both of portrait and landscape orientation screens.
-        final PackageManager pm = targetContext.getPackageManager();
-        if(!(pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
-                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT))){
-            return;
-        }
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-               OrientationTestUtils.toggleOrientation(activity);
-            }
-        });
-        instrumentation.waitForIdleSync();
-        assertTrue(mockApp.isOnConfigurationChangedCalled);
-    }
-
-}
diff --git a/tests/tests/app/src/android/app/cts/DialogTest.java b/tests/tests/app/src/android/app/cts/DialogTest.java
deleted file mode 100644
index feb4940..0000000
--- a/tests/tests/app/src/android/app/cts/DialogTest.java
+++ /dev/null
@@ -1,929 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.cts;
-
-import com.android.cts.app.stub.R;
-
-import android.app.Dialog;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.DialogInterface.OnDismissListener;
-import android.content.DialogInterface.OnKeyListener;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.cts.util.PollingCheck;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-
-import java.lang.ref.WeakReference;
-
-public class DialogTest extends ActivityInstrumentationTestCase2<DialogStubActivity> {
-
-    protected static final long SLEEP_TIME = 200;
-    private static final String STUB_ACTIVITY_PACKAGE = "com.android.cts.app.stub";
-    private static final long TEST_TIMEOUT = 1000L;
-
-    /**
-     *  please refer to Dialog
-     */
-    private static final int DISMISS = 0x43;
-    private static final int CANCEL = 0x44;
-
-    private boolean mCalledCallback;
-    private boolean mIsKey0Listened;
-    private boolean mIsKey1Listened;
-    private boolean mOnCancelListenerCalled;
-
-    private Instrumentation mInstrumentation;
-    private Context mContext;
-    private DialogStubActivity mActivity;
-
-
-    public DialogTest() {
-        super(STUB_ACTIVITY_PACKAGE, DialogStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mContext = mInstrumentation.getContext();
-    }
-
-    private void startDialogActivity(int dialogNumber) {
-        mActivity = DialogStubActivity.startDialogActivity(this, dialogNumber);
-    }
-
-    @UiThreadTest
-    public void testConstructor() {
-        new Dialog(mContext);
-        Dialog d = new Dialog(mContext, 0);
-        // According to javadoc of constructors, it will set theme to system default theme,
-        // when we set no theme id or set it theme id to 0.
-        // But CTS can no assert dialog theme equals system internal theme.
-
-        d = new Dialog(mContext, R.style.TextAppearance);
-        TypedArray ta =
-            d.getContext().getTheme().obtainStyledAttributes(R.styleable.TextAppearance);
-        assertTextAppearanceStyle(ta);
-
-        final Window w = d.getWindow();
-        ta = w.getContext().getTheme().obtainStyledAttributes(R.styleable.TextAppearance);
-        assertTextAppearanceStyle(ta);
-    }
-
-    public void testConstructor_protectedCancellable() {
-        startDialogActivity(DialogStubActivity.TEST_PROTECTED_CANCELABLE);
-        mActivity.onCancelListenerCalled = false;
-        sendKeys(KeyEvent.KEYCODE_BACK);
-        assertTrue(mActivity.onCancelListenerCalled);
-    }
-
-    public void testConstructor_protectedNotCancellable() {
-        startDialogActivity(DialogStubActivity.TEST_PROTECTED_NOT_CANCELABLE);
-        mActivity.onCancelListenerCalled = false;
-        sendKeys(KeyEvent.KEYCODE_BACK);
-        assertFalse(mActivity.onCancelListenerCalled);
-    }
-
-    private void assertTextAppearanceStyle(TypedArray ta) {
-        final int defValue = -1;
-        // get Theme and assert
-        final Resources.Theme expected = mContext.getResources().newTheme();
-        expected.setTo(mContext.getTheme());
-        expected.applyStyle(R.style.TextAppearance, true);
-        TypedArray expectedTa = expected.obtainStyledAttributes(R.styleable.TextAppearance);
-        assertEquals(expectedTa.getIndexCount(), ta.getIndexCount());
-        assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColor, defValue),
-                ta.getColor(R.styleable.TextAppearance_textColor, defValue));
-        assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColorHint, defValue),
-                ta.getColor(R.styleable.TextAppearance_textColorHint, defValue));
-        assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColorLink, defValue),
-                ta.getColor(R.styleable.TextAppearance_textColorLink, defValue));
-        assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColorHighlight, defValue),
-                ta.getColor(R.styleable.TextAppearance_textColorHighlight, defValue));
-        assertEquals(expectedTa.getDimension(R.styleable.TextAppearance_textSize, defValue),
-                ta.getDimension(R.styleable.TextAppearance_textSize, defValue));
-        assertEquals(expectedTa.getInt(R.styleable.TextAppearance_textStyle, defValue),
-                ta.getInt(R.styleable.TextAppearance_textStyle, defValue));
-    }
-
-    public void testOnStartCreateStop(){
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-
-        assertTrue(d.isOnStartCalled);
-        assertTrue(d.isOnCreateCalled);
-
-        assertFalse(d.isOnStopCalled);
-        sendKeys(KeyEvent.KEYCODE_BACK);
-        assertTrue(d.isOnStopCalled);
-    }
-
-    public void testAccessOwnerActivity() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        Dialog d = mActivity.getDialog();
-        assertNotNull(d);
-        assertSame(mActivity, d.getOwnerActivity());
-        d.setVolumeControlStream(d.getVolumeControlStream() + 1);
-        assertEquals(d.getOwnerActivity().getVolumeControlStream() + 1, d.getVolumeControlStream());
-
-        try {
-            d.setOwnerActivity(null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Dialog dialog = new Dialog(mContext);
-                assertNull(dialog.getOwnerActivity());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testShow() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        final Dialog d = mActivity.getDialog();
-        final View decor = d.getWindow().getDecorView();
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.hide();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertEquals(View.GONE, decor.getVisibility());
-        assertTrue(d.isShowing());
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.show();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertEquals(View.VISIBLE, decor.getVisibility());
-        assertTrue(d.isShowing());
-        dialogDismiss(d);
-        assertFalse(d.isShowing());
-    }
-
-    public void testOnSaveInstanceState() {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-
-        assertFalse(d.isOnSaveInstanceStateCalled);
-        assertFalse(TestDialog.isOnRestoreInstanceStateCalled);
-
-        //skip if the device doesn't support both of portrait and landscape orientation screens.
-        final PackageManager pm = mContext.getPackageManager();
-        if(!(pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
-                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT))){
-            return;
-        }
-
-        OrientationTestUtils.toggleOrientationSync(mActivity, mInstrumentation);
-
-        assertTrue(d.isOnSaveInstanceStateCalled);
-        assertTrue(TestDialog.isOnRestoreInstanceStateCalled);
-    }
-
-    public void testGetCurrentFocus() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-        assertNull(d.getCurrentFocus());
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.takeKeyEvents(true);
-                d.setContentView(R.layout.alert_dialog_text_entry);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        sendKeys(KeyEvent.KEYCODE_0);
-        // When mWindow is not null getCUrrentFocus is the view in dialog
-        assertEquals(d.getWindow().getCurrentFocus(), d.getCurrentFocus());
-    }
-
-    public void testSetContentView() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        final Dialog d = mActivity.getDialog();
-        assertNotNull(d);
-
-        // set content view to a four elements layout
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.setContentView(R.layout.alert_dialog_text_entry);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        // check if four elements are right there
-        assertNotNull(d.findViewById(R.id.username_view));
-        assertNotNull(d.findViewById(R.id.username_edit));
-        assertNotNull(d.findViewById(R.id.password_view));
-        assertNotNull(d.findViewById(R.id.password_edit));
-
-        final LayoutInflater inflate1 = d.getLayoutInflater();
-
-        // set content view to a two elements layout
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.setContentView(inflate1.inflate(R.layout.alert_dialog_text_entry_2, null));
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        // check if only two elements are right there
-        assertNotNull(d.findViewById(R.id.username_view));
-        assertNotNull(d.findViewById(R.id.username_edit));
-        assertNull(d.findViewById(R.id.password_view));
-        assertNull(d.findViewById(R.id.password_edit));
-
-        final WindowManager.LayoutParams lp = d.getWindow().getAttributes();
-        final LayoutInflater inflate2 = mActivity.getLayoutInflater();
-
-        // set content view to a four elements layout
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.setContentView(inflate2.inflate(R.layout.alert_dialog_text_entry, null), lp);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        // check if four elements are right there
-        assertNotNull(d.findViewById(R.id.username_view));
-        assertNotNull(d.findViewById(R.id.username_edit));
-        assertNotNull(d.findViewById(R.id.password_view));
-        assertNotNull(d.findViewById(R.id.password_edit));
-
-        final WindowManager.LayoutParams lp2 = d.getWindow().getAttributes();
-        final LayoutInflater inflate3 = mActivity.getLayoutInflater();
-        lp2.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-        lp2.width = ViewGroup.LayoutParams.WRAP_CONTENT;
-
-        // add a check box view
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.addContentView(inflate3.inflate(R.layout.checkbox_layout, null), lp2);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        // check if four elements are right there, and new add view there.
-        assertNotNull(d.findViewById(R.id.check_box));
-        assertNotNull(d.findViewById(R.id.username_view));
-        assertNotNull(d.findViewById(R.id.username_edit));
-        assertNotNull(d.findViewById(R.id.password_view));
-        assertNotNull(d.findViewById(R.id.password_edit));
-    }
-
-    public void testSetTitle() {
-        final String expectedTitle = "Test Dialog Without theme";
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-
-        assertNotNull(mActivity.getDialog());
-        mActivity.setUpTitle(expectedTitle);
-        mInstrumentation.waitForIdleSync();
-
-        final Dialog d = mActivity.getDialog();
-        assertEquals(expectedTitle, (String) d.getWindow().getAttributes().getTitle());
-
-        mActivity.setUpTitle(R.string.hello_android);
-        mInstrumentation.waitForIdleSync();
-        assertEquals(mActivity.getResources().getString(R.string.hello_android),
-                (String) d.getWindow().getAttributes().getTitle());
-    }
-
-    public void testOnKeyDownKeyUp() {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-        assertFalse(d.isOnKeyDownCalled);
-        assertFalse(d.isOnKeyUpCalled);
-
-        // send key 0 down and up events, onKeyDown return false
-        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
-        assertTrue(d.isOnKeyDownCalled);
-        assertTrue(d.isOnKeyUpCalled);
-        assertEquals(KeyEvent.KEYCODE_0, d.keyDownCode);
-        assertFalse(d.onKeyDownReturn);
-
-        // send key back down and up events, onKeyDown return true
-        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
-        assertEquals(KeyEvent.KEYCODE_BACK, d.keyDownCode);
-        assertTrue(d.onKeyDownReturn);
-    }
-
-     public void testOnKeyMultiple() {
-         startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-         final TestDialog d = (TestDialog) mActivity.getDialog();
-
-         assertNull(d.keyMultipleEvent);
-         d.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_UNKNOWN));
-         assertTrue(d.isOnKeyMultipleCalled);
-         assertFalse(d.onKeyMultipleReturn);
-         assertEquals(KeyEvent.KEYCODE_UNKNOWN, d.keyMultipleEvent.getKeyCode());
-         assertEquals(KeyEvent.ACTION_MULTIPLE, d.keyMultipleEvent.getAction());
-     }
-
-    public void testTouchEvent() {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-
-        assertNull(d.onTouchEvent);
-        assertNull(d.touchEvent);
-        assertFalse(d.isOnTouchEventCalled);
-
-        // Send a touch event outside the activity.  The event will be ignored
-        // because closeOnTouchOutside is false.
-        d.setCanceledOnTouchOutside(false);
-
-        long now = SystemClock.uptimeMillis();
-        MotionEvent touchMotionEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
-                1, 100, 0);
-        mInstrumentation.sendPointerSync(touchMotionEvent);
-
-        new PollingCheck(TEST_TIMEOUT) {
-            protected boolean check() {
-                return !d.dispatchTouchEventResult;
-            }
-        }.run();
-
-        assertMotionEventEquals(touchMotionEvent, d.touchEvent);
-
-        assertTrue(d.isOnTouchEventCalled);
-        assertMotionEventEquals(touchMotionEvent, d.onTouchEvent);
-        d.isOnTouchEventCalled = false;
-        assertTrue(d.isShowing());
-
-        // Watch activities cover the entire screen, so there is no way to touch outside.
-        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
-            // Send a touch event outside the activity.  This time the dialog will be dismissed
-            // because closeOnTouchOutside is true.
-            d.setCanceledOnTouchOutside(true);
-
-            touchMotionEvent = MotionEvent.obtain(now, now + 1, MotionEvent.ACTION_DOWN,
-                    1, 100, 0);
-            mInstrumentation.sendPointerSync(touchMotionEvent);
-
-            new PollingCheck(TEST_TIMEOUT) {
-                protected boolean check() {
-                    return d.dispatchTouchEventResult;
-                }
-            }.run();
-
-            assertMotionEventEquals(touchMotionEvent, d.touchEvent);
-
-            assertTrue(d.isOnTouchEventCalled);
-            assertMotionEventEquals(touchMotionEvent, d.onTouchEvent);
-            assertFalse(d.isShowing());
-        }
-    }
-
-    public void testTrackballEvent() {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-        long eventTime = SystemClock.uptimeMillis();
-        final MotionEvent trackBallEvent = MotionEvent.obtain(eventTime, eventTime,
-                MotionEvent.ACTION_DOWN, 0.0f, 0.0f, 0);
-
-        assertNull(d.trackballEvent);
-        assertNull(d.onTrackballEvent);
-
-        assertFalse(d.isOnTrackballEventCalled);
-        mInstrumentation.sendTrackballEventSync(trackBallEvent);
-        assertTrue(d.isOnTrackballEventCalled);
-        assertMotionEventEquals(trackBallEvent, d.trackballEvent);
-        assertMotionEventEquals(trackBallEvent, d.onTrackballEvent);
-
-    }
-
-    private void assertMotionEventEquals(final MotionEvent expected, final MotionEvent actual) {
-        assertEquals(expected.getDownTime(), actual.getDownTime());
-        assertEquals(expected.getEventTime(), actual.getEventTime());
-        assertEquals(expected.getAction(), actual.getAction());
-        assertEquals(expected.getMetaState(), actual.getMetaState());
-        assertEquals(expected.getSize(), actual.getSize());
-        // As MotionEvent doc says the value of X and Y coordinate may have
-        // a fraction for input devices that are sub-pixel precise,
-        // so we won't assert them here.
-    }
-
-    public void testOnWindowAttributesChanged() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-
-        assertTrue(d.isOnWindowAttributesChangedCalled);
-        d.isOnWindowAttributesChangedCalled = false;
-
-        final WindowManager.LayoutParams lp = d.getWindow().getAttributes();
-        lp.setTitle("test OnWindowAttributesChanged");
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.getWindow().setAttributes(lp);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertTrue(d.isOnWindowAttributesChangedCalled);
-        assertSame(lp, d.getWindow().getAttributes());
-    }
-
-    public void testOnContentChanged() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-        assertNotNull(d);
-
-        assertFalse(d.isOnContentChangedCalled);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.setContentView(R.layout.alert_dialog_text_entry);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertTrue(d.isOnContentChangedCalled);
-    }
-
-    public void testOnWindowFocusChanged() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-        assertTrue(d.isOnWindowFocusChangedCalled);
-        d.isOnWindowFocusChangedCalled = false;
-
-        // show a new dialog, the new dialog get focus
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.showDialog(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        // Wait until TestDialog#OnWindowFocusChanged() is called
-        new PollingCheck(TEST_TIMEOUT) {
-            protected boolean check() {
-                return d.isOnWindowFocusChangedCalled;
-            }
-        }.run();
-    }
-
-    public void testDispatchKeyEvent() {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-
-        sendKeys(KeyEvent.KEYCODE_0);
-        assertFalse(d.dispatchKeyEventResult);
-        assertEquals(KeyEvent.KEYCODE_0, d.keyEvent.getKeyCode());
-
-        d.setOnKeyListener(new OnKeyListener() {
-            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
-                if (KeyEvent.ACTION_DOWN == event.getAction()) {
-                    if (KeyEvent.KEYCODE_0 == keyCode) {
-                        mIsKey0Listened = true;
-                        return true;
-                    }
-
-                    if (KeyEvent.KEYCODE_1 == keyCode) {
-                        mIsKey1Listened = true;
-                        return true;
-                    }
-                }
-
-                return false;
-            }
-        });
-
-        mIsKey1Listened = false;
-        sendKeys(KeyEvent.KEYCODE_1);
-        assertTrue(mIsKey1Listened);
-
-        mIsKey0Listened = false;
-        sendKeys(KeyEvent.KEYCODE_0);
-        assertTrue(mIsKey0Listened);
-    }
-
-    /*
-     * Test point
-     * 1. registerForContextMenu() will OnCreateContextMenuListener on the view to this activity,
-     * so onCreateContextMenu() will be called when it is time to show the context menu.
-     * 2. Close context menu will make onPanelClosed to be called,
-     * and onPanelClosed will calls through to the new onPanelClosed method.
-     * 3. unregisterForContextMenu() will remove the OnCreateContextMenuListener on the view,
-     * so onCreateContextMenu() will not be called when try to open context menu.
-     * 4. Selected a item of context menu will make onMenuItemSelected() to be called,
-     * and onMenuItemSelected will calls through to the new onContextItemSelected method.
-     * 5. onContextMenuClosed is called whenever the context menu is being closed (either by
-     * the user canceling the menu with the back/menu button, or when an item is selected).
-     */
-    public void testContextMenu() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-        final LinearLayout parent = new LinearLayout(mContext);
-        final MockView v = new MockView(mContext);
-        parent.addView(v);
-        assertFalse(v.isShowContextMenuCalled);
-        // Register for context menu and open it
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.addContentView(parent, new LinearLayout.LayoutParams(
-                        ViewGroup.LayoutParams.MATCH_PARENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT));
-                d.registerForContextMenu(v);
-                d.openContextMenu(v);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertTrue(v.isShowContextMenuCalled);
-        assertTrue(d.isOnCreateContextMenuCalled);
-
-        assertFalse(d.isOnPanelClosedCalled);
-        assertFalse(d.isOnContextMenuClosedCalled);
-        // Closed context menu
-        sendKeys(KeyEvent.KEYCODE_BACK);
-        assertTrue(d.isOnPanelClosedCalled);
-        // Here isOnContextMenuClosedCalled should be true, see bug 1716918.
-        assertFalse(d.isOnContextMenuClosedCalled);
-
-        v.isShowContextMenuCalled = false;
-        d.isOnCreateContextMenuCalled = false;
-        // Unregister for context menu, and try to open it
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.unregisterForContextMenu(v);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.openContextMenu(v);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertTrue(v.isShowContextMenuCalled);
-        assertFalse(d.isOnCreateContextMenuCalled);
-
-        // Register for context menu and open it again
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.registerForContextMenu(v);
-                d.openContextMenu(v);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertFalse(d.isOnContextItemSelectedCalled);
-        assertFalse(d.isOnMenuItemSelectedCalled);
-        d.isOnPanelClosedCalled = false;
-        assertFalse(d.isOnContextMenuClosedCalled);
-        // select a context menu item
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        assertTrue(d.isOnMenuItemSelectedCalled);
-        // Here isOnContextItemSelectedCalled should be true, see bug 1716918.
-        assertFalse(d.isOnContextItemSelectedCalled);
-        assertTrue(d.isOnPanelClosedCalled);
-        // Here isOnContextMenuClosedCalled should be true, see bug 1716918.
-        assertFalse(d.isOnContextMenuClosedCalled);
-    }
-
-    public void testOnSearchRequested() {
-    }
-
-    public void testTakeKeyEvents() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-        final View v = d.getWindow().getDecorView();
-        assertNull(d.getCurrentFocus());
-        takeKeyEvents(d, true);
-        assertTrue(v.isFocusable());
-        sendKeys(KeyEvent.KEYCODE_0);
-        assertEquals(KeyEvent.KEYCODE_0, d.keyEvent.getKeyCode());
-        d.keyEvent = null;
-
-        takeKeyEvents(d, false);
-        assertNull(d.getCurrentFocus());
-        assertFalse(v.isFocusable());
-        sendKeys(KeyEvent.KEYCODE_0);
-        // d.keyEvent should be null
-    }
-
-    private void takeKeyEvents(final Dialog d, final boolean get) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.takeKeyEvents(get);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testRequestWindowFeature() {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        // called requestWindowFeature at TestDialog onCreate method
-        assertTrue(((TestDialog) mActivity.getDialog()).isRequestWindowFeature);
-    }
-
-    public void testSetFeatureDrawableResource() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.getDialog().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
-                        R.drawable.robot);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testSetFeatureDrawableUri() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.getDialog().setFeatureDrawableUri(Window.FEATURE_LEFT_ICON,
-                        Uri.parse("http://www.google.com"));
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testSetFeatureDrawable() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.getDialog().setFeatureDrawable(Window.FEATURE_LEFT_ICON, 
-                        new MockDrawable());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testSetFeatureDrawableAlpha() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.getDialog().setFeatureDrawableAlpha(Window.FEATURE_LEFT_ICON, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testGetLayoutInflater() {
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        final Dialog d = mActivity.getDialog();
-        assertEquals(d.getWindow().getLayoutInflater(), d.getLayoutInflater());
-    }
-
-    public void testSetCancelable_true() {
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        final Dialog d = mActivity.getDialog();
-
-        d.setCancelable(true);
-        assertTrue(d.isShowing());
-        sendKeys(KeyEvent.KEYCODE_BACK);
-        assertFalse(d.isShowing());
-    }
-
-    public void testSetCancellable_false() {
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        final Dialog d = mActivity.getDialog();
-
-        d.setCancelable(false);
-        assertTrue(d.isShowing());
-        sendKeys(KeyEvent.KEYCODE_BACK);
-        assertTrue(d.isShowing());
-    }
-
-    /*
-     * Test point
-     * 1. Cancel the dialog.
-     * 2. Set a listener to be invoked when the dialog is canceled.
-     */
-    public void testCancel_listener() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        final Dialog d = mActivity.getDialog();
-
-        assertTrue(d.isShowing());
-        mOnCancelListenerCalled = false;
-        d.setOnCancelListener(new OnCancelListener() {
-            public void onCancel(DialogInterface dialog) {
-                mOnCancelListenerCalled = true;
-            }
-        });
-        dialogCancel(d);
-
-        assertFalse(d.isShowing());
-        assertTrue(mOnCancelListenerCalled);
-    }
-
-    public void testCancel_noListener() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        final Dialog d = mActivity.getDialog();
-
-        assertTrue(d.isShowing());
-        mOnCancelListenerCalled = false;
-        d.setOnCancelListener(null);
-        dialogCancel(d);
-
-        assertFalse(d.isShowing());
-        assertFalse(mOnCancelListenerCalled);
-    }
-
-    public void testSetCancelMessage() throws Exception {
-        mCalledCallback = false;
-        startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
-        final TestDialog d = (TestDialog) mActivity.getDialog();
-        final HandlerThread ht = new HandlerThread("DialogTest");
-        ht.start();
-
-        d.setCancelMessage(new MockDismissCancelHandler(d, ht.getLooper()).obtainMessage(CANCEL,
-                new OnCancelListener() {
-                    public void onCancel(DialogInterface dialog) {
-                        mCalledCallback = true;
-                    }
-                }));
-        assertTrue(d.isShowing());
-        assertFalse(mCalledCallback);
-        sendKeys(KeyEvent.KEYCODE_BACK);
-        assertTrue(mCalledCallback);
-        assertFalse(d.isShowing());
-
-        ht.join(100);
-    }
-
-    /*
-     * Test point
-     * 1. Set a listener to be invoked when the dialog is dismissed.
-     * 2. set onDismissListener to null, it will not changed flag after dialog dismissed.
-     */
-    public void testSetOnDismissListener_listener() throws Throwable {
-        mCalledCallback = false;
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        final Dialog d = mActivity.getDialog();
-
-        d.setOnDismissListener(new OnDismissListener() {
-            public void onDismiss(DialogInterface dialog) {
-                mCalledCallback = true;
-            }
-        });
-
-        assertTrue(d.isShowing());
-        assertFalse(mCalledCallback);
-        dialogDismiss(d);
-        assertTrue(mCalledCallback);
-        assertFalse(d.isShowing());
-    }
-
-    public void testSetOnDismissListener_noListener() throws Throwable {
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        final Dialog d = mActivity.getDialog();
-        assertTrue(d.isShowing());
-        mCalledCallback = false;
-        d.setOnDismissListener(null);
-        dialogDismiss(d);
-        assertFalse(mCalledCallback);
-        assertFalse(d.isShowing());
-    }
-
-    public void testSetDismissMessage() throws Throwable {
-        mCalledCallback = false;
-        startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME);
-        final Dialog d = mActivity.getDialog();
-
-        final HandlerThread ht = new HandlerThread("DialogTest");
-        ht.start();
-
-        d.setDismissMessage(new MockDismissCancelHandler(d, ht.getLooper()).obtainMessage(DISMISS,
-                new OnDismissListener() {
-                    public void onDismiss(DialogInterface dialog) {
-                        mCalledCallback = true;
-                    }
-                }));
-        assertTrue(d.isShowing());
-        assertFalse(mCalledCallback);
-        dialogDismiss(d);
-        ht.join(100);
-        assertTrue(mCalledCallback);
-        assertFalse(d.isShowing());
-    }
-
-    private void dialogDismiss(final Dialog d) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.dismiss();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    private void dialogCancel(final Dialog d) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.cancel();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    private static class MockDismissCancelHandler extends Handler {
-        private WeakReference<DialogInterface> mDialog;
-
-        public MockDismissCancelHandler(Dialog dialog, Looper looper) {
-            super(looper);
-
-            mDialog = new WeakReference<DialogInterface>(dialog);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case DISMISS:
-                ((OnDismissListener) msg.obj).onDismiss(mDialog.get());
-                break;
-            case CANCEL:
-                ((OnCancelListener) msg.obj).onCancel(mDialog.get());
-                break;
-            }
-        }
-    }
-
-    private static class MockDrawable extends Drawable {
-        @Override
-        public void draw(Canvas canvas) {
-        }
-
-        @Override
-        public int getOpacity() {
-            return 0;
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-        }
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-        }
-    }
-
-    private static class MockView extends View {
-        public boolean isShowContextMenuCalled;
-        protected OnCreateContextMenuListener mOnCreateContextMenuListener;
-
-        public MockView(Context context) {
-            super(context);
-        }
-
-        public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) {
-            super.setOnCreateContextMenuListener(l);
-            mOnCreateContextMenuListener = l;
-        }
-
-        public OnCreateContextMenuListener getOnCreateContextMenuListener() {
-            return mOnCreateContextMenuListener;
-        }
-
-        @Override
-        public boolean showContextMenu() {
-            isShowContextMenuCalled = true;
-            return super.showContextMenu();
-        }
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/ExpandableListActivityTest.java b/tests/tests/app/src/android/app/cts/ExpandableListActivityTest.java
deleted file mode 100644
index 9d97296..0000000
--- a/tests/tests/app/src/android/app/cts/ExpandableListActivityTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.ExpandableListActivity;
-import android.content.ComponentName;
-
-public class ExpandableListActivityTest extends ActivityTestsBase {
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mIntent.putExtra("component", new ComponentName(getContext(),
-                ExpandableListTestActivity.class));
-    }
-
-    public void testSelect() {
-        runLaunchpad(LaunchpadActivity.EXPANDLIST_SELECT);
-    }
-
-    public void testView() {
-        runLaunchpad(LaunchpadActivity.EXPANDLIST_VIEW);
-    }
-
-    public void testCallback() {
-        runLaunchpad(LaunchpadActivity.EXPANDLIST_CALLBACK);
-    }
-}
\ No newline at end of file
diff --git a/tests/tests/app/src/android/app/cts/InstrumentationTest.java b/tests/tests/app/src/android/app/cts/InstrumentationTest.java
deleted file mode 100644
index 25403f3..0000000
--- a/tests/tests/app/src/android/app/cts/InstrumentationTest.java
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import com.android.cts.app.stub.R;
-
-import android.app.Activity;
-import android.app.Application;
-import android.app.Instrumentation;
-import android.app.Instrumentation.ActivityMonitor;
-import android.app.Instrumentation.ActivityResult;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.graphics.Point;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Debug;
-import android.os.IBinder;
-import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
-import android.view.InputQueue;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.Window;
-import android.view.ViewGroup.LayoutParams;
-
-import java.util.List;
-
-public class InstrumentationTest extends InstrumentationTestCase {
-
-    private static final int WAIT_TIME = 1000;
-    private Instrumentation mInstrumentation;
-    private InstrumentationTestActivity mActivity;
-    private Intent mIntent;
-    private boolean mRunOnMainSyncResult;
-    private Context mContext;
-    private MockActivity mMockActivity;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mContext = mInstrumentation.getTargetContext();
-        mIntent = new Intent(mContext, InstrumentationTestActivity.class);
-        mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mActivity = (InstrumentationTestActivity) mInstrumentation.startActivitySync(mIntent);
-    }
-
-    protected void tearDown() throws Exception {
-        mInstrumentation = null;
-        mIntent = null;
-        if (mActivity != null) {
-            mActivity.finish();
-            mActivity = null;
-        }
-        super.tearDown();
-    }
-
-    public void testConstructor() throws Exception {
-        new Instrumentation();
-    }
-
-    public void testMonitor() throws Exception {
-        if (mActivity != null)
-            mActivity.finish();
-        ActivityResult result = new ActivityResult(Activity.RESULT_OK, new Intent());
-        ActivityMonitor monitor = new ActivityMonitor(
-                InstrumentationTestActivity.class.getName(), result, false);
-        mInstrumentation.addMonitor(monitor);
-        Intent intent = new Intent(mContext, InstrumentationTestActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mContext.startActivity(intent);
-        Activity activity = mInstrumentation.waitForMonitorWithTimeout(monitor, WAIT_TIME);
-        assertTrue(activity instanceof InstrumentationTestActivity);
-        assertTrue(mInstrumentation.checkMonitorHit(monitor, 1));
-        activity.finish();
-
-        mInstrumentation.addMonitor(monitor);
-        mInstrumentation.removeMonitor(monitor);
-        Activity a = mInstrumentation.startActivitySync(intent);
-        assertTrue(a instanceof InstrumentationTestActivity);
-        activity = mInstrumentation.waitForMonitorWithTimeout(monitor, WAIT_TIME);
-        assertNull(activity);
-        a.finish();
-
-        IntentFilter filter = new IntentFilter();
-        ActivityMonitor am = mInstrumentation.addMonitor(filter, result, false);
-        mContext.startActivity(intent);
-        mInstrumentation.waitForIdleSync();
-        activity = am.waitForActivity();
-        assertTrue(activity instanceof InstrumentationTestActivity);
-        activity.finish();
-        mInstrumentation.removeMonitor(am);
-        am = mInstrumentation
-                .addMonitor(InstrumentationTestActivity.class.getName(), result, false);
-        mContext.startActivity(intent);
-        activity = am.waitForActivity();
-        assertTrue(activity instanceof InstrumentationTestActivity);
-        activity.finish();
-        mInstrumentation.removeMonitor(am);
-    }
-
-    public void testCallActivityOnCreate() throws Throwable {
-        mActivity.setOnCreateCalled(false);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mInstrumentation.callActivityOnCreate(mActivity, new Bundle());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.isOnCreateCalled());
-    }
-
-    public void testAllocCounting() throws Exception {
-        mInstrumentation.startAllocCounting();
-
-        Bundle b = mInstrumentation.getAllocCounts();
-        assertTrue(b.size() > 0);
-        b = mInstrumentation.getBinderCounts();
-        assertTrue(b.size() > 0);
-
-        int globeAllocCount = Debug.getGlobalAllocCount();
-        int globeAllocSize = Debug.getGlobalAllocSize();
-        int globeExternalAllCount = Debug.getGlobalExternalAllocCount();
-        int globeExternalAllSize = Debug.getGlobalExternalAllocSize();
-        int threadAllocCount = Debug.getThreadAllocCount();
-
-        assertTrue(Debug.getGlobalAllocCount() >= globeAllocCount);
-        assertTrue(Debug.getGlobalAllocSize() >= globeAllocSize);
-        assertTrue(Debug.getGlobalExternalAllocCount() >= globeExternalAllCount);
-        assertTrue(Debug.getGlobalExternalAllocSize() >= globeExternalAllSize);
-        assertTrue(Debug.getThreadAllocCount() >= threadAllocCount);
-
-        mInstrumentation.stopAllocCounting();
-
-        globeAllocCount = Debug.getGlobalAllocCount();
-        globeAllocSize = Debug.getGlobalAllocSize();
-        globeExternalAllCount = Debug.getGlobalExternalAllocCount();
-        globeExternalAllSize = Debug.getGlobalExternalAllocSize();
-        threadAllocCount = Debug.getThreadAllocCount();
-        assertEquals(globeAllocCount, Debug.getGlobalAllocCount());
-        assertEquals(globeAllocSize, Debug.getGlobalAllocSize());
-        assertEquals(globeExternalAllCount, Debug.getGlobalExternalAllocCount());
-        assertEquals(globeExternalAllSize, Debug.getGlobalExternalAllocSize());
-        assertEquals(threadAllocCount, Debug.getThreadAllocCount());
-    }
-
-    public void testSendTrackballEventSync() throws Exception {
-        long now = SystemClock.uptimeMillis();
-        MotionEvent orig = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
-                100, 100, 0);
-        mInstrumentation.sendTrackballEventSync(orig);
-        mInstrumentation.waitForIdleSync();
-
-        MotionEvent motionEvent = mActivity.getMotionEvent();
-        assertEquals(orig.getMetaState(), motionEvent.getMetaState());
-        assertEquals(orig.getEventTime(), motionEvent.getEventTime());
-        assertEquals(orig.getDownTime(), motionEvent.getDownTime());
-    }
-
-    public void testCallApplicationOnCreate() throws Exception {
-        InstrumentationTestStub ca = new InstrumentationTestStub();
-        mInstrumentation.callApplicationOnCreate(ca);
-        assertTrue(ca.mIsOnCreateCalled);
-    }
-
-    public void testContext() throws Exception {
-        Context c1 = mInstrumentation.getContext();
-        Context c2 = mInstrumentation.getTargetContext();
-        assertNotSame(c1.getPackageName(), c2.getPackageName());
-    }
-
-    public void testInvokeMenuActionSync() throws Exception {
-        final int resId = R.id.goto_menu_id;
-        if (mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
-            mInstrumentation.invokeMenuActionSync(mActivity, resId, 0);
-            mInstrumentation.waitForIdleSync();
-    
-            assertEquals(resId, mActivity.getMenuID());
-        }
-    }
-
-    public void testCallActivityOnPostCreate() throws Throwable {
-        mActivity.setOnPostCreate(false);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mInstrumentation.callActivityOnPostCreate(mActivity, new Bundle());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.isOnPostCreate());
-    }
-
-    public void testCallActivityOnNewIntent() throws Throwable {
-        mActivity.setOnNewIntentCalled(false);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mInstrumentation.callActivityOnNewIntent(mActivity, null);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertTrue(mActivity.isOnNewIntentCalled());
-    }
-
-    public void testCallActivityOnResume() throws Throwable {
-        mActivity.setOnResume(false);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mInstrumentation.callActivityOnResume(mActivity);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.isOnResume());
-    }
-
-    public void testMisc() throws Exception {
-    }
-
-    public void testPerformanceSnapshot() throws Exception {
-        mInstrumentation.setAutomaticPerformanceSnapshots();
-        mInstrumentation.startPerformanceSnapshot();
-        mInstrumentation.endPerformanceSnapshot();
-    }
-
-    public void testProfiling() throws Exception {
-        // by default, profiling was disabled. but after set the handleProfiling attribute in the
-        // manifest file for this Instrumentation to true, the profiling was also disabled.
-        assertFalse(mInstrumentation.isProfiling());
-
-        mInstrumentation.startProfiling();
-        mInstrumentation.stopProfiling();
-    }
-
-    public void testInvokeContextMenuAction() throws Exception {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mMockActivity = new MockActivity();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        final int id = 1;
-        final int flag = 2;
-        mInstrumentation.invokeContextMenuAction(mMockActivity, id, flag);
-        mInstrumentation.waitForIdleSync();
-
-        assertEquals(id, mMockActivity.mWindow.mId);
-        assertEquals(flag, mMockActivity.mWindow.mFlags);
-    }
-
-    public void testSendStringSync() {
-        final String text = "abcd";
-        mInstrumentation.sendStringSync(text);
-        mInstrumentation.waitForIdleSync();
-
-        List<KeyEvent> keyUpList = mActivity.getKeyUpList();
-        List<KeyEvent> keyDownList = mActivity.getKeyDownList();
-        assertEquals(text.length(), keyDownList.size());
-        assertEquals(text.length(), keyUpList.size());
-
-        KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
-        KeyEvent[] keyEvents = kcm.getEvents(text.toCharArray());
-
-        int i = 0;
-        for (int j = 0; j < keyDownList.size(); j++) {
-            assertEquals(keyEvents[i++].getKeyCode(), keyDownList.get(j).getKeyCode());
-            assertEquals(keyEvents[i++].getKeyCode(), keyUpList.get(j).getKeyCode());
-        }
-    }
-
-    public void testCallActivityOnSaveInstanceState() throws Throwable {
-        final Bundle bundle = new Bundle();
-        mActivity.setOnSaveInstanceState(false);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mInstrumentation.callActivityOnSaveInstanceState(mActivity, bundle);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertTrue(mActivity.isOnSaveInstanceState());
-        assertSame(bundle, mActivity.getBundle());
-    }
-
-    public void testSendPointerSync() throws Exception {
-        mInstrumentation.waitForIdleSync();
-        mInstrumentation.setInTouchMode(true);
-
-        // Send a touch event to the middle of the activity.
-        // We assume that the Activity is empty so there won't be anything in the middle
-        // to handle the touch.  Consequently the Activity should receive onTouchEvent
-        // because nothing else handled it.
-        Point size = new Point();
-        mActivity.getWindowManager().getDefaultDisplay().getSize(size);
-        final int x = size.x / 2;
-        final int y = size.y / 2;
-        long now = SystemClock.uptimeMillis();
-        MotionEvent orig = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
-                x, y, 0);
-        mInstrumentation.sendPointerSync(orig);
-
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.isOnTouchEventCalled());
-        mActivity.setOnTouchEventCalled(false);
-    }
-
-    public void testGetComponentName() throws Exception {
-        ComponentName com = getInstrumentation().getComponentName();
-        assertNotNull(com.getPackageName());
-        assertNotNull(com.getClassName());
-        assertNotNull(com.getShortClassName());
-    }
-
-    public void testNewApplication() throws Exception {
-        final String className = "android.app.cts.MockApplication";
-        ClassLoader cl = getClass().getClassLoader();
-
-        Application app = mInstrumentation.newApplication(cl, className, mContext);
-        assertEquals(className, app.getClass().getName());
-
-        app = Instrumentation.newApplication(MockApplication.class, mContext);
-        assertEquals(className, app.getClass().getName());
-    }
-
-    public void testRunOnMainSync() throws Exception {
-        mRunOnMainSyncResult = false;
-        mInstrumentation.runOnMainSync(new Runnable() {
-            public void run() {
-                mRunOnMainSyncResult = true;
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mRunOnMainSyncResult);
-    }
-
-    public void testCallActivityOnPause() throws Exception {
-        mActivity.setOnPauseCalled(false);
-        mInstrumentation.callActivityOnPause(mActivity);
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.isOnPauseCalled());
-    }
-
-    public void testSendKeyDownUpSync() throws Exception {
-        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
-        mInstrumentation.waitForIdleSync();
-        assertEquals(1, mActivity.getKeyUpList().size());
-        assertEquals(1, mActivity.getKeyDownList().size());
-        assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyUpList().get(0).getKeyCode());
-        assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyDownList().get(0).getKeyCode());
-    }
-
-    @UiThreadTest
-    public void testNewActivity() throws Exception {
-        Intent intent = new Intent();
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        ClassLoader cl = getClass().getClassLoader();
-        Activity activity = mInstrumentation.newActivity(cl, InstrumentationTestActivity.class
-                .getName(), intent);
-        assertEquals(InstrumentationTestActivity.class.getName(), activity.getClass().getName());
-        activity.finish();
-        activity = null;
-
-        intent = new Intent(mContext, InstrumentationTestActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        Activity father = new Activity();
-        ActivityInfo info = new ActivityInfo();
-
-        activity = mInstrumentation
-                .newActivity(InstrumentationTestActivity.class, mContext, null, null, intent, info,
-                        InstrumentationTestActivity.class.getName(), father, null, null);
-
-        assertEquals(father, activity.getParent());
-        assertEquals(InstrumentationTestActivity.class.getName(), activity.getClass().getName());
-        activity.finish();
-    }
-
-    public void testCallActivityOnStart() throws Exception {
-        mActivity.setOnStart(false);
-        mInstrumentation.callActivityOnStart(mActivity);
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.isOnStart());
-    }
-
-    public void testWaitForIdle() throws Exception {
-        MockRunnable mr = new MockRunnable();
-        assertFalse(mr.isRunCalled());
-        mInstrumentation.waitForIdle(mr);
-        Thread.sleep(WAIT_TIME);
-        assertTrue(mr.isRunCalled());
-    }
-
-    public void testSendCharacterSync() throws Exception {
-        mInstrumentation.sendCharacterSync(KeyEvent.KEYCODE_0);
-        mInstrumentation.waitForIdleSync();
-        assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyDownCode());
-        assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyUpCode());
-    }
-
-    public void testCallActivityOnRestart() throws Exception {
-        mActivity.setOnRestart(false);
-        mInstrumentation.callActivityOnRestart(mActivity);
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.isOnRestart());
-    }
-
-    public void testCallActivityOnStop() throws Exception {
-        mActivity.setOnStop(false);
-        mInstrumentation.callActivityOnStop(mActivity);
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.isOnStop());
-    }
-
-    public void testCallActivityOnUserLeaving() throws Exception {
-        assertFalse(mActivity.isOnLeave());
-        mInstrumentation.callActivityOnUserLeaving(mActivity);
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.isOnLeave());
-    }
-
-    public void testCallActivityOnRestoreInstanceState() throws Exception {
-        mActivity.setOnRestoreInstanceState(false);
-        mInstrumentation.callActivityOnRestoreInstanceState(mActivity, new Bundle());
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.isOnRestoreInstanceState());
-    }
-
-    public void testSendKeySync() throws Exception {
-        KeyEvent key = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
-        mInstrumentation.sendKeySync(key);
-        mInstrumentation.waitForIdleSync();
-        assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyDownCode());
-    }
-
-    private static class MockRunnable implements Runnable {
-        private boolean mIsRunCalled ;
-
-        public void run() {
-            mIsRunCalled = true;
-        }
-
-        public boolean isRunCalled() {
-            return mIsRunCalled;
-        }
-    }
-
-    private class MockActivity extends Activity {
-        MockWindow mWindow = new MockWindow(mContext);
-
-        @Override
-        public Window getWindow() {
-            return mWindow;
-        }
-
-        private class MockWindow extends Window {
-
-            public int mId;
-            public int mFlags;
-
-            public MockWindow(Context context) {
-                super(context);
-            }
-
-            @Override
-            public void addContentView(View view, LayoutParams params) {
-            }
-
-            @Override
-            public void closeAllPanels() {
-            }
-
-            @Override
-            public void closePanel(int featureId) {
-            }
-
-            @Override
-            public View getCurrentFocus() {
-                return null;
-            }
-
-            @Override
-            public View getDecorView() {
-                return null;
-            }
-
-            @Override
-            public LayoutInflater getLayoutInflater() {
-                return null;
-            }
-
-            @Override
-            public int getVolumeControlStream() {
-                return 0;
-            }
-
-            @Override
-            public boolean isFloating() {
-                return false;
-            }
-
-            @Override
-            public boolean isShortcutKey(int keyCode, KeyEvent event) {
-                return false;
-            }
-
-            @Override
-            protected void onActive() {
-            }
-
-            @Override
-            public void onConfigurationChanged(Configuration newConfig) {
-            }
-
-            @Override
-            public void openPanel(int featureId, KeyEvent event) {
-            }
-
-            public void alwaysReadCloseOnTouchAttr() {
-            }
-
-            @Override
-            public View peekDecorView() {
-                return null;
-            }
-
-            @Override
-            public boolean performContextMenuIdentifierAction(int id, int flags) {
-                mId = id;
-                mFlags = flags;
-                return false;
-            }
-
-            @Override
-            public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
-                return false;
-            }
-
-            @Override
-            public boolean performPanelShortcut(int featureId, int keyCode,
-                    KeyEvent event, int flags) {
-                return false;
-            }
-
-            @Override
-            public void restoreHierarchyState(Bundle savedInstanceState) {
-            }
-
-            @Override
-            public Bundle saveHierarchyState() {
-                return null;
-            }
-
-            @Override
-            public void setBackgroundDrawable(Drawable drawable) {
-            }
-
-            @Override
-            public void setChildDrawable(int featureId, Drawable drawable) {
-            }
-
-            @Override
-            public void setChildInt(int featureId, int value) {
-            }
-
-            @Override
-            public void setContentView(int layoutResID) {
-            }
-
-            @Override
-            public void setContentView(View view) {
-            }
-
-            @Override
-            public void setContentView(View view, LayoutParams params) {
-            }
-
-            @Override
-            public void setFeatureDrawable(int featureId, Drawable drawable) {
-            }
-
-            @Override
-            public void setFeatureDrawableAlpha(int featureId, int alpha) {
-            }
-
-            @Override
-            public void setFeatureDrawableResource(int featureId, int resId) {
-            }
-
-            @Override
-            public void setFeatureDrawableUri(int featureId, Uri uri) {
-            }
-
-            @Override
-            public void setFeatureInt(int featureId, int value) {
-            }
-
-            @Override
-            public void setTitle(CharSequence title) {
-            }
-
-            @Override
-            public void setTitleColor(int textColor) {
-            }
-
-            @Override
-            public void setVolumeControlStream(int streamType) {
-            }
-
-            @Override
-            public boolean superDispatchKeyEvent(KeyEvent event) {
-                return false;
-            }
-
-            @Override
-            public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
-                return false;
-            }
-
-            @Override
-            public boolean superDispatchTouchEvent(MotionEvent event) {
-                return false;
-            }
-
-            @Override
-            public boolean superDispatchTrackballEvent(MotionEvent event) {
-                return false;
-            }
-
-            @Override
-            public boolean superDispatchGenericMotionEvent(MotionEvent event) {
-                return false;
-            }
-
-            @Override
-            public void takeKeyEvents(boolean get) {
-            }
-
-            @Override
-            public void togglePanel(int featureId, KeyEvent event) {
-            }
-
-            @Override
-            public void invalidatePanelMenu(int featureId) {
-            }
-
-            @Override
-            public void takeSurface(SurfaceHolder.Callback2 callback) {
-            }
-
-            @Override
-            public void takeInputQueue(InputQueue.Callback queue) {
-            }
-
-            @Override
-            public void setStatusBarColor(int color) {
-            }
-
-            @Override
-            public int getStatusBarColor() {
-                return 0;
-            }
-
-            @Override
-            public void setNavigationBarColor(int color) {
-            }
-
-            @Override
-            public int getNavigationBarColor() {
-                return 0;
-            }
-        }
-    }
-
-    private static class InstrumentationTestStub extends Application {
-        boolean mIsOnCreateCalled = false;
-
-        @Override
-        public void onCreate() {
-            super.onCreate();
-            mIsOnCreateCalled = true;
-        }
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/Instrumentation_ActivityMonitorTest.java b/tests/tests/app/src/android/app/cts/Instrumentation_ActivityMonitorTest.java
deleted file mode 100644
index 767142c..0000000
--- a/tests/tests/app/src/android/app/cts/Instrumentation_ActivityMonitorTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.app.Instrumentation.ActivityMonitor;
-import android.app.Instrumentation.ActivityResult;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.test.InstrumentationTestCase;
-
-public class Instrumentation_ActivityMonitorTest extends InstrumentationTestCase {
-
-    private static final long WAIT_TIMEOUT = 100;
-
-    /**
-     * check points:
-     * 1 Constructor with blocking true and false
-     * 2 waitForActivity with timeout and no timeout
-     * 3 get info about ActivityMonitor
-     */
-    public void testActivityMonitor() throws Exception {
-        ActivityResult result = new ActivityResult(Activity.RESULT_OK, new Intent());
-        Instrumentation instrumentation = getInstrumentation();
-        ActivityMonitor am = instrumentation.addMonitor(
-                InstrumentationTestActivity.class.getName(), result, false);
-        Context context = instrumentation.getTargetContext();
-        Intent intent = new Intent(context, InstrumentationTestActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        context.startActivity(intent);
-        Activity lastActivity = am.getLastActivity();
-        final long TIMEOUT_MSEC = 5000;
-        long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
-        while (lastActivity == null && System.currentTimeMillis() < timeout) {
-            Thread.sleep(WAIT_TIMEOUT);
-            lastActivity = am.getLastActivity();
-        }
-        Activity activity = am.waitForActivity();
-        assertSame(activity, lastActivity);
-        assertEquals(1, am.getHits());
-        assertTrue(activity instanceof InstrumentationTestActivity);
-        activity.finish();
-        instrumentation.waitForIdleSync();
-        context.startActivity(intent);
-        timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
-        activity = null;
-        while (activity == null && System.currentTimeMillis() < timeout) {
-            Thread.sleep(WAIT_TIMEOUT);
-            activity = am.waitForActivityWithTimeout(WAIT_TIMEOUT);
-        }
-        assertNotNull(activity);
-        activity.finish();
-        instrumentation.removeMonitor(am);
-
-        am = new ActivityMonitor(InstrumentationTestActivity.class.getName(), result, true);
-        assertSame(result, am.getResult());
-        assertTrue(am.isBlocking());
-        IntentFilter which = new IntentFilter();
-        am = new ActivityMonitor(which, result, false);
-        assertSame(which, am.getFilter());
-        assertFalse(am.isBlocking());
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/IntentServiceTest.java b/tests/tests/app/src/android/app/cts/IntentServiceTest.java
deleted file mode 100644
index 42c4730..0000000
--- a/tests/tests/app/src/android/app/cts/IntentServiceTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.cts.util.PollingCheck;
-import android.os.IBinder;
-
-import java.util.concurrent.Callable;
-
-
-public class IntentServiceTest extends ActivityTestsBase {
-
-    private Intent mIntent;
-    private static final int TIMEOUT_MSEC = 30000;
-    private boolean mConnected;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        IntentServiceStub.reset();
-        mIntent = new Intent(mContext, IntentServiceStub.class);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mContext.stopService(mIntent);
-    }
-
-    public void testIntents() throws Throwable {
-        final int value = 42;
-        final int adds = 3;
-
-        Intent addIntent = new Intent(mContext, IntentServiceStub.class);
-
-        addIntent.setAction(IntentServiceStub.ISS_ADD);
-        addIntent.putExtra(IntentServiceStub.ISS_VALUE, 42);
-
-        for (int i = 0; i < adds; i++) {
-            mContext.startService(addIntent);
-        }
-
-        PollingCheck.check("onHandleIntentCalled not called enough", TIMEOUT_MSEC,
-                new Callable<Boolean>() {
-            @Override
-            public Boolean call() throws Exception {
-                return IntentServiceStub.getOnHandleIntentCalledCount() == adds;
-            }
-        });
-
-        PollingCheck.check("accumulator not correct", TIMEOUT_MSEC, new Callable<Boolean>() {
-            @Override
-            public Boolean call() throws Exception {
-                return IntentServiceStub.getAccumulator() == adds * value;
-            }
-        });
-
-        PollingCheck.check("onDestroyCalled not called", TIMEOUT_MSEC, new Callable<Boolean>() {
-            @Override
-            public Boolean call() throws Exception {
-                return IntentServiceStub.isOnDestroyCalled();
-            }
-        });
-    }
-
-    public void testIntentServiceLifeCycle() throws Throwable {
-        // start service
-        mContext.startService(mIntent);
-        new PollingCheck(TIMEOUT_MSEC) {
-            protected boolean check() {
-                return IntentServiceStub.getOnHandleIntentCalledCount() > 0;
-            }
-        }.run();
-        assertTrue(IntentServiceStub.isOnCreateCalled());
-        assertTrue(IntentServiceStub.isOnStartCalled());
-
-        // bind service
-        ServiceConnection conn = new TestConnection();
-        mContext.bindService(mIntent, conn, Context.BIND_AUTO_CREATE);
-        new PollingCheck(TIMEOUT_MSEC) {
-            protected boolean check() {
-                return mConnected;
-            }
-        }.run();
-        assertTrue(IntentServiceStub.isOnBindCalled());
-
-        // unbind service
-        mContext.unbindService(conn);
-        // stop service
-        mContext.stopService(mIntent);
-        IntentServiceStub.waitToFinish(TIMEOUT_MSEC);
-    }
-
-    private class TestConnection implements ServiceConnection {
-
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            mConnected = true;
-        }
-
-        public void onServiceDisconnected(ComponentName name) {
-        }
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/KeyguardManagerKeyguardLockTest.java b/tests/tests/app/src/android/app/cts/KeyguardManagerKeyguardLockTest.java
deleted file mode 100644
index 7a9f534..0000000
--- a/tests/tests/app/src/android/app/cts/KeyguardManagerKeyguardLockTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-
-import android.app.KeyguardManager;
-import android.test.InstrumentationTestCase;
-
-public class KeyguardManagerKeyguardLockTest extends InstrumentationTestCase {
-
-    public void testDisableKeyguard() {
-    }
-
-    public void testReenableKeyguard() {
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/KeyguardManagerTest.java b/tests/tests/app/src/android/app/cts/KeyguardManagerTest.java
deleted file mode 100644
index cb7cd4a..0000000
--- a/tests/tests/app/src/android/app/cts/KeyguardManagerTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
-
-public class KeyguardManagerTest
-        extends ActivityInstrumentationTestCase2<KeyguardManagerActivity> {
-
-    private static final String TAG = "KeyguardManagerTest";
-
-    public KeyguardManagerTest() {
-        super("com.android.cts.app.stub", KeyguardManagerActivity.class);
-    }
-
-    public void testNewKeyguardLock() {
-        final Context c = getInstrumentation().getContext();
-        final KeyguardManager keyguardManager = (KeyguardManager) c.getSystemService(
-                Context.KEYGUARD_SERVICE);
-        final KeyguardManager.KeyguardLock keyLock = keyguardManager.newKeyguardLock(TAG);
-        assertNotNull(keyLock);
-    }
-
-    public void testInKeyguardRestrictedInputMode() {
-    }
-
-    public void testExitKeyguardSecurely() {
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/LaunchTest.java b/tests/tests/app/src/android/app/cts/LaunchTest.java
deleted file mode 100644
index 26cdc20..0000000
--- a/tests/tests/app/src/android/app/cts/LaunchTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources.Theme;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.view.ContextMenu;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.WindowManager.LayoutParams;
-
-public class LaunchTest extends ActivityTestsBase {
-
-    public void testClearTopWhilResumed() {
-        mIntent.putExtra("component", new ComponentName(getContext(), ClearTop.class));
-        mIntent.putExtra(ClearTop.WAIT_CLEAR_TASK, true);
-        runLaunchpad(LaunchpadActivity.LAUNCH);
-    }
-
-    public void testClearTopInCreate() throws Exception {
-        mIntent.putExtra("component", new ComponentName(getContext(), ClearTop.class));
-        runLaunchpad(LaunchpadActivity.LAUNCH);
-    }
-
-    public void testForwardResult() {
-        runLaunchpad(LaunchpadActivity.FORWARD_RESULT);
-    }
-
-    public void testLocalScreen() {
-        mIntent.putExtra("component", new ComponentName(getContext(), LocalScreen.class));
-        runLaunchpad(LaunchpadActivity.LAUNCH);
-    }
-
-    public void testColdScreen() {
-        mIntent.putExtra("component", new ComponentName(getContext(), TestedScreen.class));
-        runLaunchpad(LaunchpadActivity.LAUNCH);
-    }
-
-    public void testLocalActivity() {
-        mIntent.putExtra("component", new ComponentName(getContext(), LocalActivity.class));
-        runLaunchpad(LaunchpadActivity.LAUNCH);
-    }
-
-    public void testColdActivity() {
-        mIntent.putExtra("component", new ComponentName(getContext(), TestedActivity.class));
-        runLaunchpad(LaunchpadActivity.LAUNCH);
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/LauncherActivityTest.java b/tests/tests/app/src/android/app/cts/LauncherActivityTest.java
deleted file mode 100644
index 3eea0b7..0000000
--- a/tests/tests/app/src/android/app/cts/LauncherActivityTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.app.LauncherActivity;
-import android.app.LauncherActivity.ListItem;
-import android.content.Context;
-import android.content.Intent;
-import android.test.InstrumentationTestCase;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.view.KeyEvent;
-
-import java.util.List;
-
-public class LauncherActivityTest
-        extends ActivityInstrumentationTestCase2<LauncherActivityStub> {
-
-    private Instrumentation mInstrumentation;
-    private LauncherActivityStub mActivity;
-
-    public LauncherActivityTest() {
-        super("com.android.cts.app.stub", LauncherActivityStub.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mActivity = getActivity();
-    }
-
-    public void testLaunchActivity() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                // Test getTargetIntent. LaunchActivity#getTargetIntent() just returns a Intent() instance
-                // with no content, so we use LaunchActivityStub#getSuperIntent() to get the default Intent,
-                // and create a new intent for other tests.
-                assertNotNull(mActivity.getSuperIntent());
-
-                // Test makeListItems. Make sure the size > 0. The sorted order is related to the sort
-                // way, so it's mutable.
-                final List<ListItem> list = mActivity.makeListItems();
-                assertTrue(list.size() > 0);
-
-                // There should be an activity(but with uncertain content) in position 0.
-                assertNotNull(mActivity.intentForPosition(0));
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        // Test onListItemClick
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        assertTrue(mActivity.isOnListItemClick);
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/LauncherActivity_IconResizerTest.java b/tests/tests/app/src/android/app/cts/LauncherActivity_IconResizerTest.java
deleted file mode 100644
index 2fdc8ec..0000000
--- a/tests/tests/app/src/android/app/cts/LauncherActivity_IconResizerTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import com.android.cts.app.stub.R;
-
-
-import android.app.LauncherActivity;
-import android.app.LauncherActivity.IconResizer;
-import android.graphics.drawable.Drawable;
-import android.test.ActivityInstrumentationTestCase2;
-
-public class LauncherActivity_IconResizerTest extends
-        ActivityInstrumentationTestCase2<LauncherActivityStub> {
-
-    private static final String PACKAGE = "com.android.cts.app.stub";
-    private LauncherActivityStub mActivity;
-
-    public LauncherActivity_IconResizerTest() {
-        super(PACKAGE, LauncherActivityStub.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
-    public void testIconResizer() throws Throwable {
-        final IconResizer ir = mActivity.new IconResizer();
-        final Drawable d = mActivity.getResources().getDrawable(R.drawable.pass);
-        assertNotNull(d);
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Drawable thumbNail = ir.createIconThumbnail(d);
-                assertNotNull(thumbNail);
-                // The size of the thumbnail is defined by inner R resource file
-                // whose details are not open.
-                assertTrue(thumbNail.getIntrinsicHeight() > 0);
-                assertTrue(thumbNail.getIntrinsicWidth() > 0);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/LauncherActivity_ListItemTest.java b/tests/tests/app/src/android/app/cts/LauncherActivity_ListItemTest.java
deleted file mode 100644
index 14ef831..0000000
--- a/tests/tests/app/src/android/app/cts/LauncherActivity_ListItemTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-
-import android.app.LauncherActivity;
-import android.test.AndroidTestCase;
-
-public class LauncherActivity_ListItemTest extends AndroidTestCase {
-    public void testConstructor() {
-        // Test public constructor
-        new LauncherActivity.ListItem();
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/LifecycleTest.java b/tests/tests/app/src/android/app/cts/LifecycleTest.java
deleted file mode 100644
index 5d2ded7..0000000
--- a/tests/tests/app/src/android/app/cts/LifecycleTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.app.cts;
-
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources.Theme;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.view.ContextMenu;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.WindowManager.LayoutParams;
-
-public class LifecycleTest extends ActivityTestsBase {
-    private Intent mTopIntent;
-    private Intent mTabIntent;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTopIntent = mIntent;
-        mTabIntent = new Intent(mContext, LaunchpadTabActivity.class);
-        mTabIntent.putExtra("tab", new ComponentName(mContext, LaunchpadActivity.class));
-    }
-
-    public void testTabDialog() {
-        mIntent = mTabIntent;
-        runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG);
-    }
-
-    public void testDialog() {
-        mIntent = mTopIntent;
-        runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG);
-    }
-
-    public void testTabScreen() {
-        mIntent = mTabIntent;
-        runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN);
-    }
-
-    public void testScreen() {
-        mIntent = mTopIntent;
-        runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN);
-    }
-
-    public void testTabBasic() {
-        mIntent = mTabIntent;
-        runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC);
-    }
-
-    public void testBasic() {
-        mIntent = mTopIntent;
-        runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC);
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/LocalActivityManagerTest.java b/tests/tests/app/src/android/app/cts/LocalActivityManagerTest.java
deleted file mode 100644
index db3baba..0000000
--- a/tests/tests/app/src/android/app/cts/LocalActivityManagerTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.app.LocalActivityManager;
-import android.content.Intent;
-import android.cts.util.CTSResult;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
-
-public class LocalActivityManagerTest extends InstrumentationTestCase implements CTSResult {
-
-    private Instrumentation mInstrumentation;
-
-    private Sync mSync = new Sync();
-    private static class Sync {
-        public boolean mHasNotify;
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mSync = new Sync();
-    }
-
-    private void setupActivity(final String action) {
-        final Intent intent = new Intent(mInstrumentation.getTargetContext(),
-                LocalActivityManagerTestHelper.class);
-        intent.setAction(action);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mInstrumentation.getTargetContext().startActivity(intent);
-    }
-
-    @UiThreadTest
-    public void testConstructor() {
-        new LocalActivityManager(new Activity(), true);
-        new LocalActivityManager(new Activity(), false);
-        new LocalActivityManager(null, false);
-        new LocalActivityManager(null, true);
-    }
-
-    public void testDispatchResume() throws InterruptedException {
-        LocalActivityManagerTestHelper.setResult(this);
-        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_RESUME);
-        waitForResult();
-    }
-
-    private void waitForResult() throws InterruptedException {
-        synchronized (mSync) {
-            if (!mSync.mHasNotify) {
-                mSync.wait();
-            }
-        }
-    }
-
-    public void testStartActivity() throws InterruptedException {
-        LocalActivityManagerTestHelper.setResult(this);
-        setupActivity(LocalActivityManagerTestHelper.ACTION_START_ACTIVITY);
-        waitForResult();
-    }
-
-    public void testDispatchCreate() throws InterruptedException {
-        LocalActivityManagerTestHelper.setResult(this);
-        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_CREATE);
-        waitForResult();
-    }
-
-    public void testDispatchStop() throws InterruptedException {
-        LocalActivityManagerTestHelper.setResult(this);
-        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_STOP);
-        waitForResult();
-    }
-
-    public void testDispatchPauseTrue() throws InterruptedException {
-        LocalActivityManagerTestHelper.setResult(this);
-        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_PAUSE_TRUE);
-        waitForResult();
-    }
-
-    public void testDispatchPauseFalse() throws InterruptedException {
-        LocalActivityManagerTestHelper.setResult(this);
-        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_PAUSE_FALSE);
-        waitForResult();
-    }
-
-    public void testSaveInstanceState() throws InterruptedException {
-        LocalActivityManagerTestHelper.setResult(this);
-        setupActivity(LocalActivityManagerTestHelper.ACTION_SAVE_INSTANCE_STATE);
-        waitForResult();
-    }
-
-    public void testDispatchDestroy() throws InterruptedException {
-        LocalActivityManagerTestHelper.setResult(this);
-        setupActivity(LocalActivityManagerTestHelper.ACTION_DISPATCH_DESTROY);
-        waitForResult();
-    }
-
-    public void testRemoveAllActivities() throws InterruptedException {
-        LocalActivityManagerTestHelper.setResult(this);
-        setupActivity(LocalActivityManagerTestHelper.ACTION_REMOVE_ALL_ACTIVITY);
-        waitForResult();
-    }
-
-    public void setResult(final int resultCode) {
-        synchronized (mSync) {
-            mSync.mHasNotify = true;
-            mSync.notify();
-            assertEquals(CTSResult.RESULT_OK, resultCode);
-        }
-    }
-
-    public void setResult(Exception e) {
-        setResult(CTSResult.RESULT_FAIL);
-    }
-
-}
diff --git a/tests/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
deleted file mode 100644
index fbb3060..0000000
--- a/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.provider.Telephony.Threads;
-import android.service.notification.StatusBarNotification;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import com.android.cts.app.stub.R;
-
-
-public class NotificationManagerTest extends AndroidTestCase {
-    final String TAG = NotificationManagerTest.class.getSimpleName();
-    final boolean DEBUG = false;
-
-    private NotificationManager mNotificationManager;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mNotificationManager = (NotificationManager) mContext.getSystemService(
-                Context.NOTIFICATION_SERVICE);
-        // clear the deck so that our getActiveNotifications results are predictable
-        mNotificationManager.cancelAll();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mNotificationManager.cancelAll();
-    }
-
-    public void testNotify() {
-        mNotificationManager.cancelAll();
-
-        final int id = 1;
-        sendNotification(id, R.drawable.black);
-        // test updating the same notification
-        sendNotification(id, R.drawable.blue);
-        sendNotification(id, R.drawable.yellow);
-
-        // assume that sendNotification tested to make sure individual notifications were present
-        StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
-        for (StatusBarNotification sbn : sbns) {
-            if (sbn.getId() != id) {
-                fail("we got back other notifications besides the one we posted: "
-                        + sbn.getKey());
-            }
-        }
-    }
-
-    public void testCancel() {
-        final int id = 9;
-        sendNotification(id, R.drawable.black);
-        mNotificationManager.cancel(id);
-
-        if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
-            fail("canceled notification was still alive, id=" + id);
-        }
-    }
-
-    public void testCancelAll() {
-        sendNotification(1, R.drawable.black);
-        sendNotification(2, R.drawable.blue);
-        sendNotification(3, R.drawable.yellow);
-
-        if (DEBUG) {
-            Log.d(TAG, "posted 3 notifications, here they are: ");
-            StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
-            for (StatusBarNotification sbn : sbns) {
-                Log.d(TAG, "  " + sbn);
-            }
-            Log.d(TAG, "about to cancel...");
-        }
-        mNotificationManager.cancelAll();
-
-        StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
-        assertTrue("notification list was not empty after cancelAll", sbns.length == 0);
-    }
-
-    private void sendNotification(final int id, final int icon) {
-        final Intent intent = new Intent(Intent.ACTION_MAIN, Threads.CONTENT_URI);
-
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
-                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        intent.setAction(Intent.ACTION_MAIN);
-
-        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
-        final Notification notification = new Notification.Builder(mContext)
-                .setSmallIcon(icon)
-                .setWhen(System.currentTimeMillis())
-                .setContentTitle("notify#" + id)
-                .setContentText("This is #" + id + "notification  ")
-                .setContentIntent(pendingIntent)
-                .build();
-        mNotificationManager.notify(id, notification);
-
-
-        if (!checkNotificationExistence(id, /*shouldExist=*/ true)) {
-            fail("couldn't find posted notification id=" + id);
-        }
-    }
-
-    private boolean checkNotificationExistence(int id, boolean shouldExist) {
-        // notification is a bit asynchronous so it may take a few ms to appear in getActiveNotifications()
-        // we will check for it for up to 200ms before giving up
-        boolean found = false;
-        for (int tries=3; tries-->0;) {
-            final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
-            for (StatusBarNotification sbn : sbns) {
-                if (sbn.getId() == id) {
-                    found = true;
-                    break;
-                }
-            }
-            if (found == shouldExist) break;
-            try {
-                Thread.sleep(100);
-            } catch (InterruptedException ex) {
-                // pass
-            }
-        }
-        return found == shouldExist;
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/NotificationTest.java b/tests/tests/app/src/android/app/cts/NotificationTest.java
deleted file mode 100644
index 6179922..0000000
--- a/tests/tests/app/src/android/app/cts/NotificationTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-import android.widget.RemoteViews;
-
-public class NotificationTest extends AndroidTestCase {
-
-    private Notification mNotification;
-    private Context mContext;
-
-    private static final String TICKER_TEXT = "tickerText";
-    private static final String CONTENT_TITLE = "contentTitle";
-    private static final String CONTENT_TEXT = "contentText";
-    private static final String URI_STRING = "uriString";
-    private static final int TOLERANCE = 200;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getContext();
-        mNotification = new Notification();
-    }
-
-    public void testConstructor() {
-        mNotification = null;
-        mNotification = new Notification();
-        assertNotNull(mNotification);
-        assertTrue(System.currentTimeMillis() - mNotification.when < TOLERANCE);
-
-        mNotification = null;
-        final int notificationTime = 200;
-        mNotification = new Notification(0, TICKER_TEXT, notificationTime);
-        assertEquals(notificationTime, mNotification.when);
-        assertEquals(0, mNotification.icon);
-        assertEquals(TICKER_TEXT, mNotification.tickerText);
-    }
-
-    public void testDescribeContents() {
-        final int expected = 0;
-        mNotification = new Notification();
-        assertEquals(expected, mNotification.describeContents());
-    }
-
-    public void testWriteToParcel() {
-        mNotification = new Notification();
-        mNotification.icon = 0;
-        mNotification.number = 1;
-        final Intent intent = new Intent();
-        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-        mNotification.contentIntent = pendingIntent;
-        final Intent deleteIntent = new Intent();
-        final PendingIntent delPendingIntent = PendingIntent.getBroadcast(
-                mContext, 0, deleteIntent, 0);
-        mNotification.deleteIntent = delPendingIntent;
-        mNotification.tickerText = TICKER_TEXT;
-
-        final RemoteViews contentView = new RemoteViews(mContext.getPackageName(),
-                android.R.layout.simple_list_item_1);
-        mNotification.contentView = contentView;
-        mNotification.defaults = 0;
-        mNotification.flags = 0;
-        final Uri uri = Uri.parse(URI_STRING);
-        mNotification.sound = uri;
-        mNotification.audioStreamType = 0;
-        final long[] longArray = { 1l, 2l, 3l };
-        mNotification.vibrate = longArray;
-        mNotification.ledARGB = 0;
-        mNotification.ledOnMS = 0;
-        mNotification.ledOffMS = 0;
-        mNotification.iconLevel = 0;
-        Parcel parcel = Parcel.obtain();
-        mNotification.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        // Test Notification(Parcel)
-        Notification result = new Notification(parcel);
-        assertEquals(mNotification.icon, result.icon);
-        assertEquals(mNotification.when, result.when);
-        assertEquals(mNotification.number, result.number);
-        assertNotNull(result.contentIntent);
-        assertNotNull(result.deleteIntent);
-        assertEquals(mNotification.tickerText, result.tickerText);
-        assertNotNull(result.contentView);
-        assertEquals(mNotification.defaults, result.defaults);
-        assertEquals(mNotification.flags, result.flags);
-        assertNotNull(result.sound);
-        assertEquals(mNotification.audioStreamType, result.audioStreamType);
-        assertEquals(mNotification.vibrate[0], result.vibrate[0]);
-        assertEquals(mNotification.vibrate[1], result.vibrate[1]);
-        assertEquals(mNotification.vibrate[2], result.vibrate[2]);
-        assertEquals(mNotification.ledARGB, result.ledARGB);
-        assertEquals(mNotification.ledOnMS, result.ledOnMS);
-        assertEquals(mNotification.ledOffMS, result.ledOffMS);
-        assertEquals(mNotification.iconLevel, result.iconLevel);
-
-        mNotification.contentIntent = null;
-        parcel = Parcel.obtain();
-        mNotification.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        result = new Notification(parcel);
-        assertNull(result.contentIntent);
-
-        mNotification.deleteIntent = null;
-        parcel = Parcel.obtain();
-        mNotification.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        result = new Notification(parcel);
-        assertNull(result.deleteIntent);
-
-        mNotification.tickerText = null;
-        parcel = Parcel.obtain();
-        mNotification.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        result = new Notification(parcel);
-        assertNull(result.tickerText);
-
-        mNotification.contentView = null;
-        parcel = Parcel.obtain();
-        mNotification.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        result = new Notification(parcel);
-        assertNull(result.contentView);
-
-        mNotification.sound = null;
-        parcel = Parcel.obtain();
-        mNotification.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        result = new Notification(parcel);
-        assertNull(result.sound);
-    }
-
-    public void testBuilder() {
-        final Intent intent = new Intent();
-        final PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-        mNotification = new Notification.Builder(mContext)
-                .setSmallIcon(1)
-                .setContentTitle(CONTENT_TITLE)
-                .setContentText(CONTENT_TEXT)
-                .setContentIntent(contentIntent)
-                .build();
-        assertEquals(CONTENT_TEXT, mNotification.extras.getString(Notification.EXTRA_TEXT));
-        assertEquals(CONTENT_TITLE, mNotification.extras.getString(Notification.EXTRA_TITLE));
-        assertEquals(1, mNotification.icon);
-        assertEquals(contentIntent, mNotification.contentIntent);
-        assertNotNull(mNotification.contentView);
-    }
-
-    public void testToString() {
-        mNotification = new Notification();
-        assertNotNull(mNotification.toString());
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/PendingIntentTest.java b/tests/tests/app/src/android/app/cts/PendingIntentTest.java
deleted file mode 100644
index d2c1b31..0000000
--- a/tests/tests/app/src/android/app/cts/PendingIntentTest.java
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-
-public class PendingIntentTest extends AndroidTestCase {
-
-    private static final int WAIT_TIME = 5000;
-    private PendingIntent mPendingIntent;
-    private Intent mIntent;
-    private Context mContext;
-    private boolean mFinishResult;
-    private boolean mHandleResult;
-    private String mResultAction;
-    private PendingIntent.OnFinished mFinish;
-    private boolean mLooperStart;
-    private Looper mLooper;
-    private Handler mHandler;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getContext();
-        mFinish = new PendingIntent.OnFinished() {
-            public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
-                    String resultData, Bundle resultExtras) {
-                mFinishResult = true;
-                if (intent != null) {
-                    mResultAction = intent.getAction();
-                }
-            }
-        };
-
-        new Thread() {
-            @Override
-            public void run() {
-                Looper.prepare();
-                mLooper = Looper.myLooper();
-                mLooperStart = true;
-                Looper.loop();
-            }
-        }.start();
-        while (!mLooperStart) {
-            Thread.sleep(50);
-        }
-        mHandler = new Handler(mLooper) {
-            @Override
-            public void dispatchMessage(Message msg) {
-                mHandleResult = true;
-                super.dispatchMessage(msg);
-            }
-
-            @Override
-            public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
-                mHandleResult = true;
-                return super.sendMessageAtTime(msg, uptimeMillis);
-            }
-
-            @Override
-            public void handleMessage(Message msg) {
-                super.handleMessage(msg);
-                mHandleResult = true;
-            }
-        };
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mLooper.quit();
-    }
-
-    public void testGetActivity() throws InterruptedException, CanceledException {
-        PendingIntentStubActivity.status = PendingIntentStubActivity.INVALIDATE;
-        mPendingIntent = null;
-        mIntent = new Intent();
-
-        mIntent.setClass(mContext, PendingIntentStubActivity.class);
-        mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-        assertEquals(mContext.getPackageName(), mPendingIntent.getTargetPackage());
-
-        mPendingIntent.send();
-
-        Thread.sleep(WAIT_TIME);
-        assertNotNull(mPendingIntent);
-        assertEquals(PendingIntentStubActivity.status, PendingIntentStubActivity.ON_CREATE);
-
-        // test getActivity return null
-        mPendingIntent.cancel();
-        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
-                PendingIntent.FLAG_NO_CREATE);
-        assertNull(mPendingIntent);
-
-        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
-                PendingIntent.FLAG_ONE_SHOT);
-
-        pendingIntentSendError(mPendingIntent);
-    }
-
-    private void pendingIntentSendError(PendingIntent pendingIntent) {
-        try {
-            // From the doc send function will throw CanceledException if the PendingIntent
-            // is no longer allowing more intents to be sent through it. So here call it twice then
-            // a CanceledException should be caught.
-            mPendingIntent.send();
-            mPendingIntent.send();
-            fail("CanceledException expected, but not thrown");
-        } catch (PendingIntent.CanceledException e) {
-            // expected
-        }
-    }
-
-    public void testGetBroadcast() throws InterruptedException, CanceledException {
-        MockReceiver.sAction = null;
-        mIntent = new Intent(MockReceiver.MOCKACTION);
-        mIntent.setClass(mContext, MockReceiver.class);
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-
-        mPendingIntent.send();
-
-        Thread.sleep(WAIT_TIME);
-        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
-
-        // test getBroadcast return null
-        mPendingIntent.cancel();
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
-                PendingIntent.FLAG_NO_CREATE);
-        assertNull(mPendingIntent);
-
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
-                PendingIntent.FLAG_ONE_SHOT);
-
-        pendingIntentSendError(mPendingIntent);
-    }
-
-    public void testGetService() throws InterruptedException, CanceledException {
-        MockService.result = false;
-        mIntent = new Intent();
-        mIntent.setClass(mContext, MockService.class);
-        mPendingIntent = PendingIntent.getService(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-
-        mPendingIntent.send();
-
-        Thread.sleep(WAIT_TIME);
-        assertTrue(MockService.result);
-
-        // test getService return null
-        mPendingIntent.cancel();
-        mPendingIntent = PendingIntent.getService(mContext, 1, mIntent,
-                PendingIntent.FLAG_NO_CREATE);
-        assertNull(mPendingIntent);
-
-        mPendingIntent = PendingIntent.getService(mContext, 1, mIntent,
-                PendingIntent.FLAG_ONE_SHOT);
-
-        pendingIntentSendError(mPendingIntent);
-    }
-
-    public void testCancel() throws CanceledException {
-        mIntent = new Intent();
-        mIntent.setClass(mContext, MockService.class);
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-
-        mPendingIntent.send();
-
-        mPendingIntent.cancel();
-        pendingIntentSendShouldFail(mPendingIntent);
-    }
-
-    private void pendingIntentSendShouldFail(PendingIntent pendingIntent) {
-        try {
-            pendingIntent.send();
-            fail("CanceledException expected, but not thrown");
-        } catch (CanceledException e) {
-            // expected
-        }
-    }
-
-    public void testSend() throws InterruptedException, CanceledException {
-        MockReceiver.sAction = null;
-        MockReceiver.sResultCode = -1;
-        mIntent = new Intent();
-        mIntent.setAction(MockReceiver.MOCKACTION);
-        mIntent.setClass(mContext, MockReceiver.class);
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-
-        mPendingIntent.send();
-
-        Thread.sleep(WAIT_TIME);
-
-        // send function to send default code 0
-        assertEquals(0, MockReceiver.sResultCode);
-        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
-        mPendingIntent.cancel();
-
-        pendingIntentSendShouldFail(mPendingIntent);
-    }
-
-    public void testSendWithParamInt() throws InterruptedException, CanceledException {
-        mIntent = new Intent(MockReceiver.MOCKACTION);
-        mIntent.setClass(mContext, MockReceiver.class);
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-        MockReceiver.sResultCode = 0;
-        MockReceiver.sAction = null;
-        // send result code 1.
-        mPendingIntent.send(1);
-        Thread.sleep(WAIT_TIME);
-        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
-
-        // assert the result code
-        assertEquals(1, MockReceiver.sResultCode);
-        assertEquals(mResultAction, null);
-
-        mResultAction = null;
-        MockReceiver.sResultCode = 0;
-        // send result code 2
-        mPendingIntent.send(2);
-        Thread.sleep(WAIT_TIME);
-
-        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
-
-        // assert the result code
-        assertEquals(2, MockReceiver.sResultCode);
-        assertEquals(MockReceiver.sAction, MockReceiver.MOCKACTION);
-        assertNull(mResultAction);
-        mPendingIntent.cancel();
-        pendingIntentSendShouldFail(mPendingIntent);
-    }
-
-    public void testSendWithParamContextIntIntent() throws InterruptedException, CanceledException {
-        mIntent = new Intent(MockReceiver.MOCKACTION);
-        mIntent.setClass(mContext, MockReceiver.class);
-
-        MockReceiver.sAction = null;
-        MockReceiver.sResultCode = 0;
-
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
-
-        mPendingIntent.send(mContext, 1, null);
-        Thread.sleep(WAIT_TIME);
-
-        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
-        assertEquals(1, MockReceiver.sResultCode);
-        mPendingIntent.cancel();
-
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
-        MockReceiver.sAction = null;
-        MockReceiver.sResultCode = 0;
-
-        mPendingIntent.send(mContext, 2, mIntent);
-        Thread.sleep(WAIT_TIME);
-        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
-        assertEquals(2, MockReceiver.sResultCode);
-        mPendingIntent.cancel();
-    }
-
-    public void testSendWithParamIntOnFinishedHandler() throws InterruptedException,
-            CanceledException {
-        mIntent = new Intent(MockReceiver.MOCKACTION);
-        mIntent.setClass(mContext, MockReceiver.class);
-
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
-        mFinishResult = false;
-        mHandleResult = false;
-        MockReceiver.sAction = null;
-        MockReceiver.sResultCode = 0;
-
-        mPendingIntent.send(1, null, null);
-        Thread.sleep(WAIT_TIME);
-        assertFalse(mFinishResult);
-        assertFalse(mHandleResult);
-        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
-
-        // assert result code
-        assertEquals(1, MockReceiver.sResultCode);
-        mPendingIntent.cancel();
-
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
-        mFinishResult = false;
-        MockReceiver.sAction = null;
-        MockReceiver.sResultCode = 0;
-        mHandleResult = false;
-
-        mPendingIntent.send(2, mFinish, null);
-        Thread.sleep(WAIT_TIME);
-        assertTrue(mFinishResult);
-        assertFalse(mHandleResult);
-        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
-
-        // assert result code
-        assertEquals(2, MockReceiver.sResultCode);
-        mPendingIntent.cancel();
-
-        mHandleResult = false;
-        mFinishResult = false;
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
-        MockReceiver.sAction = null;
-        mPendingIntent.send(3, mFinish, mHandler);
-        Thread.sleep(WAIT_TIME);
-        assertTrue(mHandleResult);
-        assertTrue(mFinishResult);
-        assertEquals(MockReceiver.MOCKACTION, MockReceiver.sAction);
-
-        // assert result code
-        assertEquals(3, MockReceiver.sResultCode);
-        mPendingIntent.cancel();
-    }
-
-    public void testSendWithParamContextIntIntentOnFinishedHandler() throws InterruptedException,
-            CanceledException {
-        mIntent = new Intent(MockReceiver.MOCKACTION);
-        mIntent.setAction(MockReceiver.MOCKACTION);
-
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
-        mFinishResult = false;
-        mResultAction = null;
-        mHandleResult = false;
-        mPendingIntent.send(mContext, 1, mIntent, null, null);
-        Thread.sleep(WAIT_TIME);
-        assertFalse(mFinishResult);
-        assertFalse(mHandleResult);
-        assertNull(mResultAction);
-        mPendingIntent.cancel();
-
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
-        mFinishResult = false;
-        mResultAction = null;
-        mHandleResult = false;
-        mPendingIntent.send(mContext, 1, mIntent, mFinish, null);
-        Thread.sleep(WAIT_TIME);
-        assertTrue(mFinishResult);
-        assertEquals(mResultAction, MockReceiver.MOCKACTION);
-        assertFalse(mHandleResult);
-        mPendingIntent.cancel();
-
-        mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
-        mFinishResult = false;
-        mResultAction = null;
-        mHandleResult = false;
-        mPendingIntent.send(mContext, 1, mIntent, mFinish, mHandler);
-        Thread.sleep(WAIT_TIME);
-        assertTrue(mHandleResult);
-        assertEquals(mResultAction, MockReceiver.MOCKACTION);
-        assertTrue(mFinishResult);
-        mPendingIntent.cancel();
-    }
-
-    public void testGetTargetPackage() {
-        mIntent = new Intent();
-        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-        assertEquals(mContext.getPackageName(), mPendingIntent.getTargetPackage());
-    }
-
-    public void testEquals() {
-        mIntent = new Intent();
-        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-
-        PendingIntent target = PendingIntent.getActivity(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-
-        assertFalse(mPendingIntent.equals(target));
-        assertFalse(mPendingIntent.hashCode() == target.hashCode());
-        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent, 1);
-
-        target = PendingIntent.getActivity(mContext, 1, mIntent, 1);
-        assertTrue(mPendingIntent.equals(target));
-
-        mIntent = new Intent(MockReceiver.MOCKACTION);
-        target = PendingIntent.getBroadcast(mContext, 1, mIntent, 1);
-        assertFalse(mPendingIntent.equals(target));
-        assertFalse(mPendingIntent.hashCode() == target.hashCode());
-
-        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent, 1);
-        target = PendingIntent.getActivity(mContext, 1, mIntent, 1);
-
-        assertTrue(mPendingIntent.equals(target));
-        assertEquals(mPendingIntent.hashCode(), target.hashCode());
-    }
-
-    public void testDescribeContents() {
-        mIntent = new Intent();
-        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-        final int expected = 0;
-        assertEquals(expected, mPendingIntent.describeContents());
-    }
-
-    public void testWriteToParcel() {
-        mIntent = new Intent();
-        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-        Parcel parcel = Parcel.obtain();
-
-        mPendingIntent.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        PendingIntent pendingIntent = PendingIntent.CREATOR.createFromParcel(parcel);
-        assertTrue(mPendingIntent.equals(pendingIntent));
-    }
-
-    public void testReadAndWritePendingIntentOrNullToParcel() {
-        mIntent = new Intent();
-        mPendingIntent = PendingIntent.getActivity(mContext, 1, mIntent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
-        assertNotNull(mPendingIntent.toString());
-
-        Parcel parcel = Parcel.obtain();
-        PendingIntent.writePendingIntentOrNullToParcel(mPendingIntent, parcel);
-        parcel.setDataPosition(0);
-        PendingIntent target = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
-        assertEquals(mPendingIntent, target);
-        assertEquals(mPendingIntent.getTargetPackage(), target.getTargetPackage());
-
-        mPendingIntent = null;
-        parcel = Parcel.obtain();
-        PendingIntent.writePendingIntentOrNullToParcel(mPendingIntent, parcel);
-        target = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
-        assertNull(target);
-    }
-
-}
diff --git a/tests/tests/app/src/android/app/cts/ProgressDialogTest.java b/tests/tests/app/src/android/app/cts/ProgressDialogTest.java
deleted file mode 100644
index b2037b6..0000000
--- a/tests/tests/app/src/android/app/cts/ProgressDialogTest.java
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-
-import android.app.Instrumentation;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.view.KeyEvent;
-import android.view.Window;
-import android.widget.ProgressBar;
-
-/**
- * Test {@link ProgressDialog}.
- */
-public class ProgressDialogTest extends ActivityInstrumentationTestCase2<MockActivity> {
-    private final CharSequence TITLE = "title";
-    private final CharSequence MESSAGE = "message";
-
-    private boolean mCanceled;
-    private Drawable mDrawable;
-    private Drawable mActualDrawableNull;
-    private Drawable mActualDrawable;
-    private ProgressBar mProgressBar;
-    private int mProgress1;
-    private int mProgress2;
-
-    private Context mContext;
-    private Instrumentation mInstrumentation;
-    private MockActivity mActivity;
-
-    public ProgressDialogTest() {
-        super("com.android.cts.app.stub", MockActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mCanceled = false;
-        mInstrumentation = getInstrumentation();
-        mActivity = getActivity();
-        mContext = mActivity;
-        mDrawable = getActivity().getResources().getDrawable(
-                com.android.cts.app.stub.R.drawable.yellow);
-    }
-
-    @UiThreadTest
-    public void testProgressDialog1(){
-        new ProgressDialog(mContext);
-    }
-
-    @UiThreadTest
-    public void testProgressDialog2(){
-        new ProgressDialog(mContext, com.android.cts.app.stub.R.style.Theme_AlertDialog);
-    }
-
-    @UiThreadTest
-    public void testOnStartCreateStop() {
-        MockProgressDialog pd = new MockProgressDialog(mContext);
-
-        assertFalse(pd.mIsOnCreateCalled);
-        assertFalse(pd.mIsOnStartCalled);
-        pd.show();
-        assertTrue(pd.mIsOnCreateCalled);
-        assertTrue(pd.mIsOnStartCalled);
-
-        assertFalse(pd.mIsOnStopCalled);
-        pd.dismiss();
-        assertTrue(pd.mIsOnStopCalled);
-    }
-
-    @UiThreadTest
-    public void testShow1() {
-        ProgressDialog.show(mContext, TITLE, MESSAGE);
-    }
-
-    @UiThreadTest
-    public void testShow2() {
-        ProgressDialog dialog = ProgressDialog.show(mContext, TITLE, MESSAGE, false);
-
-        /*
-         * note: the progress bar's style only supports indeterminate mode,
-         * so can't change indeterminate
-         */
-        assertTrue(dialog.isIndeterminate());
-
-        dialog = ProgressDialog.show(mContext, TITLE, MESSAGE, true);
-        assertTrue(dialog.isIndeterminate());
-    }
-
-    public void testShow3() throws Throwable {
-        final OnCancelListener cL = new OnCancelListener(){
-            public void onCancel(DialogInterface dialog) {
-                mCanceled = true;
-            }
-        };
-
-        // cancelable is false
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                ProgressDialog dialog = ProgressDialog.show(mContext, TITLE, MESSAGE, true, false);
-
-                dialog.setOnCancelListener(cL);
-                dialog.onBackPressed();
-                dialog.dismiss();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertFalse(mCanceled);
-
-        // cancelable is true
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                ProgressDialog dialog = ProgressDialog.show(mContext, TITLE, MESSAGE, true, true);
-                assertFalse(mCanceled);
-                dialog.setOnCancelListener(cL);
-                dialog.onBackPressed();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertTrue(mCanceled);
-    }
-
-    public void testShow4() throws Throwable {
-        final OnCancelListener cL = new OnCancelListener(){
-            public void onCancel(DialogInterface dialog) {
-                mCanceled = true;
-            }
-        };
-
-        // cancelable is false
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                ProgressDialog dialog = ProgressDialog.show(
-                        mContext, TITLE, MESSAGE, true, false, cL);
-
-                dialog.onBackPressed();
-                dialog.dismiss();;
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertFalse(mCanceled);
-
-        // cancelable is true
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                ProgressDialog dialog = ProgressDialog.show(
-                        mContext, TITLE, MESSAGE, true, true, cL);
-
-                assertFalse(mCanceled);
-                dialog.onBackPressed();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-
-        assertTrue(mCanceled);
-    }
-
-    @UiThreadTest
-    public void testAccessMax() {
-        // progressDialog is null
-        ProgressDialog progressDialog = buildDialog();
-        progressDialog.setMax(2008);
-        assertEquals(2008, progressDialog.getMax());
-
-        // progressDialog is not null
-        progressDialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
-        progressDialog.setMax(2009);
-        assertEquals(2009, progressDialog.getMax());
-    }
-
-    @UiThreadTest
-    public void testAccessProgress() {
-        // progressDialog is null
-        ProgressDialog progressDialog = buildDialog();
-        progressDialog.setProgress(11);
-        assertEquals(11, progressDialog.getProgress());
-
-        /* progressDialog is not null
-         * note: the progress bar's style only supports indeterminate mode,
-         * so can't change progress
-         */
-        progressDialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
-        progressDialog.setProgress(12);
-        assertEquals(0, progressDialog.getProgress());
-    }
-
-    @UiThreadTest
-    public void testAccessSecondaryProgress() {
-        // dialog is null
-        ProgressDialog dialog = buildDialog();
-        dialog.setSecondaryProgress(17);
-        assertEquals(17, dialog.getSecondaryProgress());
-
-        /* mProgress is not null
-         * note: the progress bar's style only supports indeterminate mode,
-         * so can't change secondary progress
-         */
-        dialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
-        dialog.setSecondaryProgress(18);
-        assertEquals(0, dialog.getSecondaryProgress());
-    }
-
-    @UiThreadTest
-    public void testSetIndeterminate() {
-        // progress is null
-        ProgressDialog dialog = buildDialog();
-        dialog.setIndeterminate(true);
-        assertTrue(dialog.isIndeterminate());
-        dialog.setIndeterminate(false);
-        assertFalse(dialog.isIndeterminate());
-
-        /* mProgress is not null
-         * note: the progress bar's style only supports indeterminate mode,
-         * so can't change indeterminate
-         */
-        dialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
-        dialog.setIndeterminate(true);
-        assertTrue(dialog.isIndeterminate());
-        dialog.setIndeterminate(false);
-        assertTrue(dialog.isIndeterminate());
-    }
-
-    @UiThreadTest
-    public void testIncrementProgressBy() throws Throwable {
-        ProgressDialog dialog = new ProgressDialog(mContext);
-        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
-        dialog.show();
-        dialog.setProgress(10);
-        mProgress1 = dialog.getProgress();
-        dialog.incrementProgressBy(60);
-        mProgress2 = dialog.getProgress();
-        dialog.cancel();
-
-        assertEquals(10, mProgress1);
-        assertEquals(70, mProgress2);
-    }
-
-    @UiThreadTest
-    public void testIncrementSecondaryProgressBy() throws Throwable {
-        ProgressDialog dialog = new ProgressDialog(mContext);
-        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
-        dialog.show();
-        dialog.setSecondaryProgress(10);
-        mProgress1 = dialog.getSecondaryProgress();
-        dialog.incrementSecondaryProgressBy(60);
-        mProgress2 = dialog.getSecondaryProgress();
-
-        assertEquals(10, mProgress1);
-        assertEquals(70, mProgress2);
-    }
-
-    @UiThreadTest
-    public void testSetProgressDrawable() throws Throwable {
-        ProgressDialog dialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
-        Window w = dialog.getWindow();
-        ProgressBar progressBar = (ProgressBar) w.findViewById(android.R.id.progress);
-
-        dialog.setProgressDrawable(mDrawable);
-        mActualDrawable = progressBar.getProgressDrawable();
-
-        dialog.setProgressDrawable(null);
-        mActualDrawableNull = progressBar.getProgressDrawable();
-        assertEquals(mDrawable, mActualDrawable);
-        assertEquals(null, mActualDrawableNull);
-    }
-
-    @UiThreadTest
-    public void testSetIndeterminateDrawable() throws Throwable {
-        ProgressDialog dialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
-        Window w = dialog.getWindow();
-        mProgressBar = (ProgressBar) w.findViewById(android.R.id.progress);
-
-        dialog.setIndeterminateDrawable(mDrawable);
-        mActualDrawable = mProgressBar.getIndeterminateDrawable();
-        assertEquals(mDrawable, mActualDrawable);
-
-        dialog.setIndeterminateDrawable(null);
-        mActualDrawableNull = mProgressBar.getIndeterminateDrawable();
-        assertEquals(null, mActualDrawableNull);
-    }
-
-    @UiThreadTest
-    public void testSetMessage() throws Throwable {
-        ProgressDialog dialog = new ProgressDialog(mContext);
-        dialog = new ProgressDialog(mContext);
-        dialog.setMessage(MESSAGE);
-        dialog.show();
-        // dialog is not null
-        dialog = ProgressDialog.show(mContext, TITLE, MESSAGE);
-        dialog.setMessage("Chuck Norris");
-    }
-
-    @UiThreadTest
-    public void testSetProgressStyle() throws Throwable {
-        ProgressDialog dialog = new ProgressDialog(mContext);
-        setProgressStyle(dialog, ProgressDialog.STYLE_HORIZONTAL);
-        setProgressStyle(dialog, ProgressDialog.STYLE_SPINNER);
-        setProgressStyle(dialog, 100);
-    }
-
-    private void setProgressStyle(ProgressDialog dialog, int style) {
-        dialog.setProgressStyle(style);
-        dialog.show();
-        dialog.setProgress(10);
-        dialog.setMax(100);
-    }
-
-    private static class MockProgressDialog extends ProgressDialog {
-        public boolean mIsOnStopCalled;
-        public boolean mIsOnStartCalled;
-        public boolean mIsOnCreateCalled;
-
-        public MockProgressDialog(Context context) {
-            super(context);
-        }
-
-        @Override
-        protected void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            mIsOnCreateCalled = true;
-        }
-
-        @Override
-        public void onStart(){
-            super.onStart();
-            mIsOnStartCalled = true;
-        }
-
-        @Override
-        public void onStop() {
-            super.onStop();
-            mIsOnStopCalled = true;
-        }
-    }
-
-    private ProgressDialog buildDialog() {
-        return new ProgressDialog(mContext);
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/SearchManagerTest.java b/tests/tests/app/src/android/app/cts/SearchManagerTest.java
deleted file mode 100644
index 1cece76..0000000
--- a/tests/tests/app/src/android/app/cts/SearchManagerTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.content.Intent;
-import android.cts.util.CTSResult;
-
-public class SearchManagerTest extends CTSActivityTestCaseBase {
-
-    private void setupActivity(String action) {
-        Intent intent = new Intent();
-        intent.setAction(action);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.setClass(getInstrumentation().getTargetContext(), SearchManagerStubActivity.class);
-        getInstrumentation().getTargetContext().startActivity(intent);
-    }
-
-    public void testStopSearch() throws InterruptedException {
-        SearchManagerStubActivity.setCTSResult(this);
-        setupActivity(SearchManagerStubActivity.TEST_STOP_SEARCH);
-        waitForResult();
-    }
-
-    public void testSetOnDismissListener() throws InterruptedException {
-        SearchManagerStubActivity.setCTSResult(this);
-        setupActivity(SearchManagerStubActivity.TEST_ON_DISMISSLISTENER);
-        waitForResult();
-    }
-
-    public void testSetOnCancelListener() throws InterruptedException {
-        SearchManagerStubActivity.setCTSResult(this);
-        setupActivity(SearchManagerStubActivity.TEST_ON_CANCELLISTENER);
-        waitForResult();
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/ServiceTest.java b/tests/tests/app/src/android/app/cts/ServiceTest.java
deleted file mode 100644
index 8ba1816..0000000
--- a/tests/tests/app/src/android/app/cts/ServiceTest.java
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.cts.util.IBinderParcelable;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
-import android.test.suitebuilder.annotation.MediumTest;
-
-public class ServiceTest extends ActivityTestsBase {
-    private static final int STATE_START_1 = 0;
-    private static final int STATE_START_2 = 1;
-    private static final int STATE_UNBIND = 2;
-    private static final int STATE_DESTROY = 3;
-    private static final int STATE_REBIND = 4;
-    private static final int STATE_UNBIND_ONLY = 5;
-    private static final int DELAY = 5000;
-    private static final
-        String EXIST_CONN_TO_RECEIVE_SERVICE = "existing connection to receive service";
-    private static final String EXIST_CONN_TO_LOSE_SERVICE = "existing connection to lose service";
-    private int mExpectedServiceState;
-    private Context mContext;
-    private Intent mLocalService;
-    private Intent mLocalDeniedService;
-    private Intent mLocalGrantedService;
-    private Intent mLocalService_ApplicationHasPermission;
-    private Intent mLocalService_ApplicationDoesNotHavePermission;
-
-    private IBinder mStateReceiver;
-
-    private static class EmptyConnection implements ServiceConnection {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-        }
-    }
-
-    private class TestConnection implements ServiceConnection {
-        private final boolean mExpectDisconnect;
-        private final boolean mSetReporter;
-        private boolean mMonitor;
-        private int mCount;
-
-        public TestConnection(boolean expectDisconnect, boolean setReporter) {
-            mExpectDisconnect = expectDisconnect;
-            mSetReporter = setReporter;
-            mMonitor = !setReporter;
-        }
-
-        void setMonitor(boolean v) {
-            mMonitor = v;
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (mSetReporter) {
-                Parcel data = Parcel.obtain();
-                data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
-                data.writeStrongBinder(mStateReceiver);
-                try {
-                    service.transact(LocalService.SET_REPORTER_CODE, data, null, 0);
-                } catch (RemoteException e) {
-                    finishBad("DeadObjectException when sending reporting object");
-                }
-                data.recycle();
-            }
-
-            if (mMonitor) {
-                mCount++;
-                if (mExpectedServiceState == STATE_START_1) {
-                    if (mCount == 1) {
-                        finishGood();
-                    } else {
-                        finishBad("onServiceConnected() again on an object when it "
-                                + "should have been the first time");
-                    }
-                } else if (mExpectedServiceState == STATE_START_2) {
-                    if (mCount == 2) {
-                        finishGood();
-                    } else {
-                        finishBad("onServiceConnected() the first time on an object "
-                                + "when it should have been the second time");
-                    }
-                } else {
-                    finishBad("onServiceConnected() called unexpectedly");
-                }
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            if (mMonitor) {
-                if (mExpectedServiceState == STATE_DESTROY) {
-                    if (mExpectDisconnect) {
-                        finishGood();
-                    } else {
-                        finishBad("onServiceDisconnected() when it shouldn't have been");
-                    }
-                } else {
-                    finishBad("onServiceDisconnected() called unexpectedly");
-                }
-            }
-        }
-    }
-
-    private void startExpectResult(Intent service) {
-        startExpectResult(service, new Bundle());
-    }
-
-    private void startExpectResult(Intent service, Bundle bundle) {
-        bundle.putParcelable(LocalService.REPORT_OBJ_NAME, new IBinderParcelable(mStateReceiver));
-
-        boolean success = false;
-        try {
-            mExpectedServiceState = STATE_START_1;
-            mContext.startService(new Intent(service).putExtras(bundle));
-            waitForResultOrThrow(DELAY, "service to start first time");
-            mExpectedServiceState = STATE_START_2;
-            mContext.startService(new Intent(service).putExtras(bundle));
-            waitForResultOrThrow(DELAY, "service to start second time");
-            success = true;
-        } finally {
-            if (!success) {
-                mContext.stopService(service);
-            }
-        }
-        mExpectedServiceState = STATE_DESTROY;
-        mContext.stopService(service);
-        waitForResultOrThrow(DELAY, "service to be destroyed");
-    }
-
-    /**
-     * test the service lifecycle, a service can be used in two ways:
-     * 1  It can be started and allowed to run until someone stops it or it stops itself.
-     *    In this mode, it's started by calling Context.startService()
-     *    and stopped by calling Context.stopService().
-     *    It can stop itself by calling Service.stopSelf() or Service.stopSelfResult().
-     *    Only one stopService() call is needed to stop the service,
-     *    no matter how many times startService() was called.
-     * 2  It can be operated programmatically using an interface that it defines and exports.
-     *    Clients establish a connection to the Service object
-     *    and use that connection to call into the service.
-     *    The connection is established by calling Context.bindService(),
-     *    and is closed by calling Context.unbindService().
-     *    Multiple clients can bind to the same service.
-     *    If the service has not already been launched, bindService() can optionally launch it.
-     */
-    private void bindExpectResult(Intent service) {
-        TestConnection conn = new TestConnection(true, false);
-        TestConnection conn2 = new TestConnection(false, false);
-        boolean success = false;
-        try {
-            // Expect to see the TestConnection connected.
-            mExpectedServiceState = STATE_START_1;
-            mContext.bindService(service, conn, 0);
-            mContext.startService(service);
-            waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
-
-            // Expect to see the second TestConnection connected.
-            mContext.bindService(service, conn2, 0);
-            waitForResultOrThrow(DELAY, "new connection to receive service");
-
-            mContext.unbindService(conn2);
-            success = true;
-        } finally {
-            if (!success) {
-                mContext.unbindService(conn);
-                mContext.unbindService(conn2);
-                mContext.stopService(service);
-            }
-        }
-
-        // Expect to see the TestConnection disconnected.
-        mExpectedServiceState = STATE_DESTROY;
-        mContext.stopService(service);
-        waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
-
-        mContext.unbindService(conn);
-
-        conn = new TestConnection(true, true);
-        success = false;
-        try {
-            // Expect to see the TestConnection connected.
-            conn.setMonitor(true);
-            mExpectedServiceState = STATE_START_1;
-            mContext.bindService(service, conn, 0);
-            mContext.startService(service);
-            waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
-
-            success = true;
-        } finally {
-            if (!success) {
-                mContext.unbindService(conn);
-                mContext.stopService(service);
-            }
-        }
-
-        // Expect to see the service unbind and then destroyed.
-        conn.setMonitor(false);
-        mExpectedServiceState = STATE_UNBIND;
-        mContext.stopService(service);
-        waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
-
-        mContext.unbindService(conn);
-
-        conn = new TestConnection(true, true);
-        success = false;
-        try {
-            // Expect to see the TestConnection connected.
-            conn.setMonitor(true);
-            mExpectedServiceState = STATE_START_1;
-            mContext.bindService(service, conn, 0);
-            mContext.startService(service);
-            waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
-
-            success = true;
-        } finally {
-            if (!success) {
-                mContext.unbindService(conn);
-                mContext.stopService(service);
-            }
-        }
-
-        // Expect to see the service unbind but not destroyed.
-        conn.setMonitor(false);
-        mExpectedServiceState = STATE_UNBIND_ONLY;
-        mContext.unbindService(conn);
-        waitForResultOrThrow(DELAY, "existing connection to unbind service");
-
-        // Expect to see the service rebound.
-        mExpectedServiceState = STATE_REBIND;
-        mContext.bindService(service, conn, 0);
-        waitForResultOrThrow(DELAY, "existing connection to rebind service");
-
-        // Expect to see the service unbind and then destroyed.
-        mExpectedServiceState = STATE_UNBIND;
-        mContext.stopService(service);
-        waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
-
-        mContext.unbindService(conn);
-    }
-
-    /**
-     * test automatically create the service as long as the binding exists
-     * and disconnect from an application service
-     */
-    private void bindAutoExpectResult(Intent service) {
-        TestConnection conn = new TestConnection(false, true);
-        boolean success = false;
-        try {
-            conn.setMonitor(true);
-            mExpectedServiceState = STATE_START_1;
-            mContext.bindService(
-                    service, conn, Context.BIND_AUTO_CREATE);
-            waitForResultOrThrow(DELAY, "connection to start and receive service");
-            success = true;
-        } finally {
-            if (!success) {
-                mContext.unbindService(conn);
-            }
-        }
-        mExpectedServiceState = STATE_UNBIND;
-        mContext.unbindService(conn);
-        waitForResultOrThrow(DELAY, "disconnecting from service");
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getContext();
-        mLocalService = new Intent(mContext, LocalService.class);
-        mLocalDeniedService = new Intent(mContext, LocalDeniedService.class);
-        mLocalGrantedService = new Intent(mContext, LocalGrantedService.class);
-        mLocalService_ApplicationHasPermission = new Intent(
-                LocalService.SERVICE_LOCAL_GRANTED, null /*uri*/, mContext, LocalService.class);
-        mLocalService_ApplicationDoesNotHavePermission = new Intent(
-                LocalService.SERVICE_LOCAL_DENIED, null /*uri*/, mContext, LocalService.class);
-        mStateReceiver = new MockBinder();
-    }
-
-    private class MockBinder extends Binder {
-        @Override
-        protected boolean onTransact(int code, Parcel data, Parcel reply,
-                int flags) throws RemoteException {
-            if (code == LocalService.STARTED_CODE) {
-                data.enforceInterface(LocalService.SERVICE_LOCAL);
-                int count = data.readInt();
-                if (mExpectedServiceState == STATE_START_1) {
-                    if (count == 1) {
-                        finishGood();
-                    } else {
-                        finishBad("onStart() again on an object when it "
-                                + "should have been the first time");
-                    }
-                } else if (mExpectedServiceState == STATE_START_2) {
-                    if (count == 2) {
-                        finishGood();
-                    } else {
-                        finishBad("onStart() the first time on an object when it "
-                                + "should have been the second time");
-                    }
-                } else {
-                    finishBad("onStart() was called when not expected (state="
-                            + mExpectedServiceState + ")");
-                }
-                return true;
-            } else if (code == LocalService.DESTROYED_CODE) {
-                data.enforceInterface(LocalService.SERVICE_LOCAL);
-                if (mExpectedServiceState == STATE_DESTROY) {
-                    finishGood();
-                } else {
-                    finishBad("onDestroy() was called when not expected (state="
-                            + mExpectedServiceState + ")");
-                }
-                return true;
-            } else if (code == LocalService.UNBIND_CODE) {
-                data.enforceInterface(LocalService.SERVICE_LOCAL);
-                if (mExpectedServiceState == STATE_UNBIND) {
-                    mExpectedServiceState = STATE_DESTROY;
-                } else if (mExpectedServiceState == STATE_UNBIND_ONLY) {
-                    finishGood();
-                } else {
-                    finishBad("onUnbind() was called when not expected (state="
-                            + mExpectedServiceState + ")");
-                }
-                return true;
-            } else if (code == LocalService.REBIND_CODE) {
-                data.enforceInterface(LocalService.SERVICE_LOCAL);
-                if (mExpectedServiceState == STATE_REBIND) {
-                    finishGood();
-                } else {
-                    finishBad("onRebind() was called when not expected (state="
-                            + mExpectedServiceState + ")");
-                }
-                return true;
-            } else {
-                return super.onTransact(code, data, reply, flags);
-            }
-        }
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mContext.stopService(mLocalService);
-        mContext.stopService(mLocalGrantedService);
-        mContext.stopService(mLocalService_ApplicationHasPermission);
-    }
-
-    public void testLocalStartClass() throws Exception {
-        startExpectResult(mLocalService);
-    }
-
-    public void testLocalStartAction() throws Exception {
-        startExpectResult(new Intent(
-                LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
-    }
-
-    public void testLocalBindClass() throws Exception {
-        bindExpectResult(mLocalService);
-    }
-
-    @MediumTest
-    public void testLocalBindAction() throws Exception {
-        bindExpectResult(new Intent(
-                LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
-    }
-
-    @MediumTest
-    public void testLocalBindAutoClass() throws Exception {
-        bindAutoExpectResult(mLocalService);
-    }
-
-    @MediumTest
-    public void testLocalBindAutoAction() throws Exception {
-        bindAutoExpectResult(new Intent(
-                LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
-    }
-
-    @MediumTest
-    public void testLocalStartClassPermissions() throws Exception {
-        startExpectResult(mLocalGrantedService);
-        startExpectResult(mLocalDeniedService);
-    }
-
-    @MediumTest
-    public void testLocalStartActionPermissions() throws Exception {
-        startExpectResult(mLocalService_ApplicationHasPermission);
-        startExpectResult(mLocalService_ApplicationDoesNotHavePermission);
-    }
-
-    @MediumTest
-    public void testLocalBindClassPermissions() throws Exception {
-        bindExpectResult(mLocalGrantedService);
-        bindExpectResult(mLocalDeniedService);
-    }
-
-    @MediumTest
-    public void testLocalBindActionPermissions() throws Exception {
-        bindExpectResult(mLocalService_ApplicationHasPermission);
-        bindExpectResult(mLocalService_ApplicationDoesNotHavePermission);
-    }
-
-    @MediumTest
-    public void testLocalBindAutoClassPermissionGranted() throws Exception {
-        bindAutoExpectResult(mLocalGrantedService);
-    }
-
-    @MediumTest
-    public void testLocalBindAutoActionPermissionGranted() throws Exception {
-        bindAutoExpectResult(mLocalService_ApplicationHasPermission);
-    }
-
-    @MediumTest
-    public void testLocalUnbindTwice() throws Exception {
-        EmptyConnection conn = new EmptyConnection();
-        mContext.bindService(
-                mLocalService_ApplicationHasPermission, conn, 0);
-        mContext.unbindService(conn);
-        try {
-            mContext.unbindService(conn);
-            fail("No exception thrown on the second unbind");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @MediumTest
-    public void testImplicitIntentFailsOnApiLevel21() throws Exception {
-        Intent intent = new Intent(LocalService.SERVICE_LOCAL);
-        EmptyConnection conn = new EmptyConnection();
-        try {
-            mContext.bindService(intent, conn, 0);
-            mContext.unbindService(conn);
-            fail("Implicit intents should be disallowed for apps targeting API 21+");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
deleted file mode 100644
index 4e57d31..0000000
--- a/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * 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.
- */
-
-package android.app.cts;
-
-import android.app.ActivityManager;
-import android.app.Instrumentation;
-import android.app.WallpaperManager;
-import android.bluetooth.BluetoothAdapter;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.hardware.Camera;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
-import android.hardware.Camera.CameraInfo;
-import android.hardware.Camera.Parameters;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CameraManager;
-import android.hardware.camera2.CameraMetadata;
-import android.location.LocationManager;
-import android.net.sip.SipManager;
-import android.net.wifi.WifiManager;
-import android.nfc.NfcAdapter;
-import android.telephony.TelephonyManager;
-import android.test.InstrumentationTestCase;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Test for checking that the {@link PackageManager} is reporting the correct features.
- */
-public class SystemFeaturesTest extends InstrumentationTestCase {
-
-    private Context mContext;
-    private PackageManager mPackageManager;
-    private HashSet<String> mAvailableFeatures;
-
-    private ActivityManager mActivityManager;
-    private LocationManager mLocationManager;
-    private SensorManager mSensorManager;
-    private TelephonyManager mTelephonyManager;
-    private WifiManager mWifiManager;
-    private CameraManager mCameraManager;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        Instrumentation instrumentation = getInstrumentation();
-        mContext = instrumentation.getTargetContext();
-        mPackageManager = mContext.getPackageManager();
-        mAvailableFeatures = new HashSet<String>();
-        if (mPackageManager.getSystemAvailableFeatures() != null) {
-            for (FeatureInfo feature : mPackageManager.getSystemAvailableFeatures()) {
-                mAvailableFeatures.add(feature.name);
-            }
-        }
-        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
-        mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
-        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
-        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-        mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
-    }
-
-    /**
-     * Check for features improperly prefixed with "android." that are not defined in
-     * {@link PackageManager}.
-     */
-    public void testFeatureNamespaces() throws IllegalArgumentException, IllegalAccessException {
-        Set<String> officialFeatures = getFeatureConstantsNames("FEATURE_");
-        assertFalse(officialFeatures.isEmpty());
-
-        Set<String> notOfficialFeatures = new HashSet<String>(mAvailableFeatures);
-        notOfficialFeatures.removeAll(officialFeatures);
-
-        for (String featureName : notOfficialFeatures) {
-            if (featureName != null) {
-                assertFalse("Use a different namespace than 'android' for " + featureName,
-                        featureName.startsWith("android"));
-            }
-        }
-    }
-
-    public void testBluetoothFeature() {
-        if (BluetoothAdapter.getDefaultAdapter() != null) {
-            assertAvailable(PackageManager.FEATURE_BLUETOOTH);
-        } else {
-            assertNotAvailable(PackageManager.FEATURE_BLUETOOTH);
-        }
-    }
-
-    public void testCameraFeatures() throws Exception {
-        int numCameras = Camera.getNumberOfCameras();
-        if (numCameras == 0) {
-            assertNotAvailable(PackageManager.FEATURE_CAMERA);
-            assertNotAvailable(PackageManager.FEATURE_CAMERA_AUTOFOCUS);
-            assertNotAvailable(PackageManager.FEATURE_CAMERA_FLASH);
-            assertNotAvailable(PackageManager.FEATURE_CAMERA_FRONT);
-            assertNotAvailable(PackageManager.FEATURE_CAMERA_ANY);
-            assertNotAvailable(PackageManager.FEATURE_CAMERA_LEVEL_FULL);
-            assertNotAvailable(PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR);
-            assertNotAvailable(PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING);
-            assertNotAvailable(PackageManager.FEATURE_CAMERA_CAPABILITY_RAW);
-
-            assertFalse("Devices supporting external cameras must have a representative camera " +
-                    "connected for testing",
-                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
-        } else {
-            assertAvailable(PackageManager.FEATURE_CAMERA_ANY);
-            checkFrontCamera();
-            checkRearCamera();
-            checkCamera2Features();
-        }
-    }
-
-    private void checkCamera2Features() throws Exception {
-        String[] cameraIds = mCameraManager.getCameraIdList();
-        boolean fullCamera = false;
-        boolean manualSensor = false;
-        boolean manualPostProcessing = false;
-        boolean raw = false;
-        CameraCharacteristics[] cameraChars = new CameraCharacteristics[cameraIds.length];
-        for (String cameraId : cameraIds) {
-            CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(cameraId);
-            Integer hwLevel = chars.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
-            int[] capabilities = chars.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
-            if (hwLevel == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL) {
-                fullCamera = true;
-            }
-            for (int capability : capabilities) {
-                switch (capability) {
-                    case CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
-                        manualSensor = true;
-                        break;
-                    case CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING:
-                        manualPostProcessing = true;
-                        break;
-                    case CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW:
-                        raw = true;
-                        break;
-                    default:
-                        // Capabilities don't have a matching system feature
-                        break;
-                }
-            }
-        }
-        assertFeature(fullCamera, PackageManager.FEATURE_CAMERA_LEVEL_FULL);
-        assertFeature(manualSensor, PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR);
-        assertFeature(manualPostProcessing,
-                PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING);
-        assertFeature(raw, PackageManager.FEATURE_CAMERA_CAPABILITY_RAW);
-    }
-
-    private void checkFrontCamera() {
-        CameraInfo info = new CameraInfo();
-        int numCameras = Camera.getNumberOfCameras();
-        int frontCameraId = -1;
-        for (int i = 0; i < numCameras; i++) {
-            Camera.getCameraInfo(i, info);
-            if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
-                frontCameraId = i;
-            }
-        }
-
-        if (frontCameraId > -1) {
-            assertTrue("Device has front-facing camera but does not report either " +
-                    "the FEATURE_CAMERA_FRONT or FEATURE_CAMERA_EXTERNAL feature",
-                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT) ||
-                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
-        } else {
-            assertFalse("Device does not have front-facing camera but reports either " +
-                    "the FEATURE_CAMERA_FRONT or FEATURE_CAMERA_EXTERNAL feature",
-                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT) ||
-                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
-        }
-    }
-
-    private void checkRearCamera() {
-        Camera camera = null;
-        try {
-            camera = Camera.open();
-            if (camera != null) {
-                assertAvailable(PackageManager.FEATURE_CAMERA);
-
-                Camera.Parameters params = camera.getParameters();
-                if (params.getSupportedFocusModes().contains(Parameters.FOCUS_MODE_AUTO)) {
-                    assertAvailable(PackageManager.FEATURE_CAMERA_AUTOFOCUS);
-                } else {
-                    assertNotAvailable(PackageManager.FEATURE_CAMERA_AUTOFOCUS);
-                }
-
-                if (params.getFlashMode() != null) {
-                    assertAvailable(PackageManager.FEATURE_CAMERA_FLASH);
-                } else {
-                    assertNotAvailable(PackageManager.FEATURE_CAMERA_FLASH);
-                }
-            } else {
-                assertNotAvailable(PackageManager.FEATURE_CAMERA);
-                assertNotAvailable(PackageManager.FEATURE_CAMERA_AUTOFOCUS);
-                assertNotAvailable(PackageManager.FEATURE_CAMERA_FLASH);
-            }
-        } finally {
-            if (camera != null) {
-                camera.release();
-            }
-        }
-    }
-
-    public void testLiveWallpaperFeature() {
-        try {
-            Intent intent = new Intent(WallpaperManager.ACTION_LIVE_WALLPAPER_CHOOSER);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            mContext.startActivity(intent);
-            assertAvailable(PackageManager.FEATURE_LIVE_WALLPAPER);
-        } catch (ActivityNotFoundException e) {
-            assertNotAvailable(PackageManager.FEATURE_LIVE_WALLPAPER);
-        }
-    }
-
-    public void testLocationFeatures() {
-        if (mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
-            assertAvailable(PackageManager.FEATURE_LOCATION);
-            assertAvailable(PackageManager.FEATURE_LOCATION_GPS);
-        } else {
-            assertNotAvailable(PackageManager.FEATURE_LOCATION_GPS);
-        }
-
-        if (mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
-            assertAvailable(PackageManager.FEATURE_LOCATION);
-            assertAvailable(PackageManager.FEATURE_LOCATION_NETWORK);
-        } else {
-            assertNotAvailable(PackageManager.FEATURE_LOCATION_NETWORK);
-        }
-    }
-
-    public void testNfcFeatures() {
-        if (NfcAdapter.getDefaultAdapter(mContext) != null) {
-            assertAvailable(PackageManager.FEATURE_NFC);
-            assertAvailable(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
-        } else {
-            assertNotAvailable(PackageManager.FEATURE_NFC);
-        }
-    }
-
-    public void testScreenFeatures() {
-        assertTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
-                || mPackageManager.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT));
-    }
-
-    /**
-     * Check that the sensor features reported by the PackageManager correspond to the sensors
-     * returned by {@link SensorManager#getSensorList(int)}.
-     */
-    public void testSensorFeatures() throws Exception {
-        Set<String> featuresLeft = getFeatureConstantsNames("FEATURE_SENSOR_");
-
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_ACCELEROMETER,
-                Sensor.TYPE_ACCELEROMETER);
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_BAROMETER,
-                Sensor.TYPE_PRESSURE);
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_COMPASS,
-                Sensor.TYPE_MAGNETIC_FIELD);
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_GYROSCOPE,
-                Sensor.TYPE_GYROSCOPE);
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_LIGHT,
-                Sensor.TYPE_LIGHT);
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_PROXIMITY,
-                Sensor.TYPE_PROXIMITY);
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_STEP_COUNTER,
-                Sensor.TYPE_STEP_COUNTER);
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_STEP_DETECTOR,
-                Sensor.TYPE_STEP_DETECTOR);
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_AMBIENT_TEMPERATURE,
-                Sensor.TYPE_AMBIENT_TEMPERATURE);
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_RELATIVE_HUMIDITY,
-                Sensor.TYPE_RELATIVE_HUMIDITY);
-
-
-        /*
-         * We have three cases to test for :
-         * Case 1:  Device does not have an HRM
-         * FEATURE_SENSOR_HEART_RATE               false
-         * FEATURE_SENSOR_HEART_RATE_ECG           false
-         * assertFeatureForSensor(TYPE_HEART_RATE) false
-         *
-         * Case 2:  Device has a PPG HRM
-         * FEATURE_SENSOR_HEART_RATE               true
-         * FEATURE_SENSOR_HEART_RATE_ECG           false
-         * assertFeatureForSensor(TYPE_HEART_RATE) true
-         *
-         * Case 3:  Device has an ECG HRM
-         * FEATURE_SENSOR_HEART_RATE               false
-         * FEATURE_SENSOR_HEART_RATE_ECG           true
-         * assertFeatureForSensor(TYPE_HEART_RATE) true
-         */
-
-        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HEART_RATE_ECG)) {
-                /* Case 3 for FEATURE_SENSOR_HEART_RATE_ECG true case */
-                assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE_ECG,
-                        Sensor.TYPE_HEART_RATE);
-
-                /* Remove HEART_RATE from featuresLeft, no way to test that one */
-                assertTrue("Features left " + featuresLeft + " to check did not include "
-                        + PackageManager.FEATURE_SENSOR_HEART_RATE,
-                        featuresLeft.remove(PackageManager.FEATURE_SENSOR_HEART_RATE));
-        } else if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HEART_RATE)) {
-                /* Case 1 & 2 for FEATURE_SENSOR_HEART_RATE_ECG false case */
-                assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE_ECG,
-                        Sensor.TYPE_HEART_RATE);
-
-                /* Case 1 & 3 for FEATURE_SENSOR_HEART_RATE false case */
-                assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE,
-                        Sensor.TYPE_HEART_RATE);
-        } else {
-                /* Case 2 for FEATURE_SENSOR_HEART_RATE true case */
-                assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE,
-                        Sensor.TYPE_HEART_RATE);
-
-                /* Remove HEART_RATE_ECG from featuresLeft, no way to test that one */
-                assertTrue("Features left " + featuresLeft + " to check did not include "
-                        + PackageManager.FEATURE_SENSOR_HEART_RATE_ECG,
-                        featuresLeft.remove(PackageManager.FEATURE_SENSOR_HEART_RATE_ECG));
-        }
-
-        assertTrue("Assertions need to be added to this test for " + featuresLeft,
-                featuresLeft.isEmpty());
-    }
-
-    /** Get a list of feature constants in PackageManager matching a prefix. */
-    private static Set<String> getFeatureConstantsNames(String prefix)
-            throws IllegalArgumentException, IllegalAccessException {
-        Set<String> features = new HashSet<String>();
-        Field[] fields = PackageManager.class.getFields();
-        for (Field field : fields) {
-            if (field.getName().startsWith(prefix)) {
-                String feature = (String) field.get(null);
-                features.add(feature);
-            }
-        }
-        return features;
-    }
-
-    public void testSipFeatures() {
-        if (SipManager.newInstance(mContext) != null) {
-            assertAvailable(PackageManager.FEATURE_SIP);
-        } else {
-            assertNotAvailable(PackageManager.FEATURE_SIP);
-            assertNotAvailable(PackageManager.FEATURE_SIP_VOIP);
-        }
-
-        if (SipManager.isApiSupported(mContext)) {
-            assertAvailable(PackageManager.FEATURE_SIP);
-        } else {
-            assertNotAvailable(PackageManager.FEATURE_SIP);
-            assertNotAvailable(PackageManager.FEATURE_SIP_VOIP);
-        }
-
-        if (SipManager.isVoipSupported(mContext)) {
-            assertAvailable(PackageManager.FEATURE_SIP);
-            assertAvailable(PackageManager.FEATURE_SIP_VOIP);
-        } else {
-            assertNotAvailable(PackageManager.FEATURE_SIP_VOIP);
-        }
-    }
-
-    /**
-     * Check that if the PackageManager declares a sensor feature that the device has at least
-     * one sensor that matches that feature. Also check that if a PackageManager does not declare
-     * a sensor that the device also does not have such a sensor.
-     *
-     * @param featuresLeft to check in order to make sure the test covers all sensor features
-     * @param expectedFeature that the PackageManager may report
-     * @param expectedSensorType that that {@link SensorManager#getSensorList(int)} may have
-     */
-    private void assertFeatureForSensor(Set<String> featuresLeft, String expectedFeature,
-            int expectedSensorType) {
-        assertTrue("Features left " + featuresLeft + " to check did not include "
-                + expectedFeature, featuresLeft.remove(expectedFeature));
-
-        boolean hasSensorFeature = mPackageManager.hasSystemFeature(expectedFeature);
-
-        List<Sensor> sensors = mSensorManager.getSensorList(expectedSensorType);
-        List<String> sensorNames = new ArrayList<String>(sensors.size());
-        for (Sensor sensor : sensors) {
-            sensorNames.add(sensor.getName());
-        }
-        boolean hasSensorType = !sensors.isEmpty();
-
-        String message = "PackageManager#hasSystemFeature(" + expectedFeature + ") returns "
-                + hasSensorFeature
-                + " but SensorManager#getSensorList(" + expectedSensorType + ") shows sensors "
-                + sensorNames;
-
-        assertEquals(message, hasSensorFeature, hasSensorType);
-    }
-
-    /**
-     * Check that the {@link TelephonyManager#getPhoneType()} matches the reported features.
-     */
-    public void testTelephonyFeatures() {
-        int phoneType = mTelephonyManager.getPhoneType();
-        switch (phoneType) {
-            case TelephonyManager.PHONE_TYPE_GSM:
-                assertAvailable(PackageManager.FEATURE_TELEPHONY);
-                assertAvailable(PackageManager.FEATURE_TELEPHONY_GSM);
-                break;
-
-            case TelephonyManager.PHONE_TYPE_CDMA:
-                assertAvailable(PackageManager.FEATURE_TELEPHONY);
-                assertAvailable(PackageManager.FEATURE_TELEPHONY_CDMA);
-                break;
-
-            case TelephonyManager.PHONE_TYPE_NONE:
-                assertNotAvailable(PackageManager.FEATURE_TELEPHONY);
-                assertNotAvailable(PackageManager.FEATURE_TELEPHONY_CDMA);
-                assertNotAvailable(PackageManager.FEATURE_TELEPHONY_GSM);
-                break;
-
-            default:
-                throw new IllegalArgumentException("Did you add a new phone type? " + phoneType);
-        }
-    }
-
-    public void testTouchScreenFeatures() {
-        ConfigurationInfo configInfo = mActivityManager.getDeviceConfigurationInfo();
-        if (configInfo.reqTouchScreen != Configuration.TOUCHSCREEN_NOTOUCH) {
-            assertAvailable(PackageManager.FEATURE_TOUCHSCREEN);
-            assertAvailable(PackageManager.FEATURE_FAKETOUCH);
-        } else {
-            assertNotAvailable(PackageManager.FEATURE_TOUCHSCREEN);
-        }
-
-        // TODO: Add tests for the other touchscreen features.
-    }
-
-    public void testUsbAccessory() {
-        assertAvailable(PackageManager.FEATURE_USB_ACCESSORY);
-    }
-
-    public void testWifiFeature() throws Exception {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
-            // no WiFi, skip the test
-            return;
-        }
-        boolean enabled = mWifiManager.isWifiEnabled();
-        try {
-            // WifiManager is hard-coded to return true,
-            // the case without WiFi is already handled,
-            // so this case MUST have WiFi.
-            if (mWifiManager.setWifiEnabled(true)) {
-                assertAvailable(PackageManager.FEATURE_WIFI);
-            }
-        } finally {
-            if (!enabled) {
-                mWifiManager.setWifiEnabled(false);
-            }
-        }
-    }
-
-    private void assertAvailable(String feature) {
-        assertTrue("PackageManager#hasSystemFeature should return true for " + feature,
-                mPackageManager.hasSystemFeature(feature));
-        assertTrue("PackageManager#getSystemAvailableFeatures should have " + feature,
-                mAvailableFeatures.contains(feature));
-    }
-
-    private void assertNotAvailable(String feature) {
-        assertFalse("PackageManager#hasSystemFeature should NOT return true for " + feature,
-                mPackageManager.hasSystemFeature(feature));
-        assertFalse("PackageManager#getSystemAvailableFeatures should NOT have " + feature,
-                mAvailableFeatures.contains(feature));
-    }
-
-    private void assertFeature(boolean exist, String feature) {
-        if (exist) {
-            assertAvailable(feature);
-        } else {
-            assertNotAvailable(feature);
-        }
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/TabActivityTest.java b/tests/tests/app/src/android/app/cts/TabActivityTest.java
deleted file mode 100644
index 9c028a1..0000000
--- a/tests/tests/app/src/android/app/cts/TabActivityTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.app.TabActivity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
-import android.widget.TabHost;
-
-public class TabActivityTest extends InstrumentationTestCase {
-    private Instrumentation mInstrumentation;
-    private MockTabActivity mActivity;
-    private Activity mChildActivity;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = super.getInstrumentation();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        if (mActivity != null) {
-            if (!mActivity.isFinishing()) {
-                mActivity.finish();
-            } else if (mChildActivity != null) {
-                if (!mChildActivity.isFinishing()) {
-                    mChildActivity.finish();
-                }
-            }
-        }
-        super.tearDown();
-    }
-
-    public void testTabActivity() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                // Test constructor
-                new TabActivity();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        final String packageName = "com.android.cts.app.stub";
-        final Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.setClassName(packageName, MockTabActivity.class.getName());
-        mActivity = (MockTabActivity) mInstrumentation.startActivitySync(intent);
-        // Test onPostCreate, onContentChanged. These two methods are invoked in starting
-        // activity. Default values of isOnContentChangedCalled, isOnPostCreateCalled are false.
-        assertTrue(mActivity.isOnContentChangedCalled);
-        assertTrue(mActivity.isOnPostCreateCalled);
-
-        // Can't get default value.
-        final int defaultIndex = 1;
-        mActivity.setDefaultTab(defaultIndex);
-        final String defaultTab = "DefaultTab";
-        mActivity.setDefaultTab(defaultTab);
-        // Test getTabHost, getTabWidget
-        final TabHost tabHost = mActivity.getTabHost();
-        assertNotNull(tabHost);
-        assertNotNull(tabHost.getTabWidget());
-    }
-
-    @UiThreadTest
-    public void testChildTitleCallback() throws Exception {
-        final Context context = mInstrumentation.getTargetContext();
-        final Intent intent = new Intent(context, MockTabActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        final MockTabActivity father = new MockTabActivity();
-        final ComponentName componentName = new ComponentName(context, MockTabActivity.class);
-        final ActivityInfo info = context.getPackageManager().getActivityInfo(componentName, 0);
-        mChildActivity = mInstrumentation.newActivity(MockTabActivity.class, mInstrumentation
-                .getTargetContext(), null, null, intent, info, MockTabActivity.class.getName(),
-                father, null, null);
-
-        assertNotNull(mChildActivity);
-        final String newTitle = "New Title";
-        mChildActivity.setTitle(newTitle);
-        assertTrue(father.isOnChildTitleChangedCalled);
-    }
-}
diff --git a/tests/tests/app/src/android/app/cts/TimePickerDialogTest.java b/tests/tests/app/src/android/app/cts/TimePickerDialogTest.java
deleted file mode 100644
index 79a91a1..0000000
--- a/tests/tests/app/src/android/app/cts/TimePickerDialogTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-
-import android.app.TimePickerDialog;
-import android.app.TimePickerDialog.OnTimeSetListener;
-import android.content.Context;
-import android.os.Bundle;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.widget.TimePicker;
-
-/**
- * Test {@link TimePickerDialog}.
- */
-public class TimePickerDialogTest extends ActivityInstrumentationTestCase2<DialogStubActivity> {
-    private static final String HOUR = "hour";
-    private static final String MINUTE = "minute";
-    private static final String IS_24_HOUR = "is24hour";
-
-    private static final int TARGET_HOUR = 15;
-    private static final int TARGET_MINUTE = 9;
-
-    private int mCallbackHour;
-    private int mCallbackMinute;
-
-    private OnTimeSetListener mOnTimeSetListener;
-
-    private Context mContext;
-    private DialogStubActivity mActivity;
-
-    public TimePickerDialogTest() {
-        super("com.android.cts.app.stub", DialogStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContext = getInstrumentation().getContext();
-        mOnTimeSetListener = new OnTimeSetListener(){
-            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
-                mCallbackHour = hourOfDay;
-                mCallbackMinute = minute;
-            }
-        };
-    }
-
-    @UiThreadTest
-    public void testSaveInstanceState() {
-        TimePickerDialog tD = new TimePickerDialog(
-            mContext, mOnTimeSetListener, TARGET_HOUR, TARGET_MINUTE, true);
-
-        Bundle b = tD.onSaveInstanceState();
-
-        assertEquals(TARGET_HOUR, b.getInt(HOUR));
-        assertEquals(TARGET_MINUTE, b.getInt(MINUTE));
-        assertTrue(b.getBoolean(IS_24_HOUR));
-
-        int minute = 13;
-        tD = new TimePickerDialog(
-                mContext, com.android.cts.app.stub.R.style.Theme_AlertDialog,
-                    mOnTimeSetListener, TARGET_HOUR, minute, false);
-
-        b = tD.onSaveInstanceState();
-
-        assertEquals(TARGET_HOUR, b.getInt(HOUR));
-        assertEquals(minute, b.getInt(MINUTE));
-        assertFalse(b.getBoolean(IS_24_HOUR));
-    }
-
-    @UiThreadTest
-    public void testOnClick() {
-        TimePickerDialog timePickerDialog = buildDialog();
-        timePickerDialog.onClick(null, TimePickerDialog.BUTTON_POSITIVE);
-
-        assertEquals(TARGET_HOUR, mCallbackHour);
-        assertEquals(TARGET_MINUTE, mCallbackMinute);
-    }
-
-    public void testOnTimeChanged() throws Throwable {
-        final int minute = 34;
-        startDialogActivity(DialogStubActivity.TEST_TIMEPICKERDIALOG);
-        final TimePickerDialog d = (TimePickerDialog) mActivity.getDialog();
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                d.onTimeChanged(null, TARGET_HOUR, minute);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-
-    }
-
-    @UiThreadTest
-    public void testUpdateTime() {
-        TimePickerDialog timePickerDialog = buildDialog();
-        int minute = 18;
-        timePickerDialog.updateTime(TARGET_HOUR, minute);
-
-        // here call onSaveInstanceState is to check the data put by updateTime
-        Bundle b = timePickerDialog.onSaveInstanceState();
-
-        assertEquals(TARGET_HOUR, b.getInt(HOUR));
-        assertEquals(minute, b.getInt(MINUTE));
-    }
-
-    @UiThreadTest
-    public void testOnRestoreInstanceState() {
-        int minute = 27;
-        Bundle b1 = new Bundle();
-        b1.putInt(HOUR, TARGET_HOUR);
-        b1.putInt(MINUTE, minute);
-        b1.putBoolean(IS_24_HOUR, false);
-
-        TimePickerDialog timePickerDialog = buildDialog();
-        timePickerDialog.onRestoreInstanceState(b1);
-
-        //here call onSaveInstanceState is to check the data put by onRestoreInstanceState
-        Bundle b2 = timePickerDialog.onSaveInstanceState();
-
-        assertEquals(TARGET_HOUR, b2.getInt(HOUR));
-        assertEquals(minute, b2.getInt(MINUTE));
-        assertFalse(b2.getBoolean(IS_24_HOUR));
-    }
-
-    private void startDialogActivity(int dialogNumber) {
-        mActivity = DialogStubActivity.startDialogActivity(this, dialogNumber);
-    }
-
-    private TimePickerDialog buildDialog() {
-        return new TimePickerDialog(
-                mContext, mOnTimeSetListener, TARGET_HOUR, TARGET_MINUTE, true);
-    }
-}
diff --git a/tests/tests/appwidget/Android.mk b/tests/tests/appwidget/Android.mk
index 8641d53..28052d2 100644
--- a/tests/tests/appwidget/Android.mk
+++ b/tests/tests/appwidget/Android.mk
@@ -26,4 +26,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/appwidget/AndroidManifest.xml b/tests/tests/appwidget/AndroidManifest.xml
index 4d9b61d..6f7d053 100644
--- a/tests/tests/appwidget/AndroidManifest.xml
+++ b/tests/tests/appwidget/AndroidManifest.xml
@@ -17,7 +17,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.cts.appwidget">
+    package="android.appwidget.cts">
 
   <application>
       <uses-library android:name="android.test.runner"/>
@@ -45,7 +45,7 @@
   </application>
 
   <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-      android:targetPackage="android.cts.appwidget"
+      android:targetPackage="android.appwidget.cts"
       android:label="Tests for the app widget APIs.">
       <meta-data android:name="listener"
           android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/appwidget/AndroidTest.xml b/tests/tests/appwidget/AndroidTest.xml
new file mode 100644
index 0000000..fcee457
--- /dev/null
+++ b/tests/tests/appwidget/AndroidTest.xml
@@ -0,0 +1,24 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS App Widget test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAppWidgetTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.appwidget.cts" />
+        <option name="runtime-hint" value="3m30s" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
index a385ebe..61b964d 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
@@ -40,7 +40,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.cts.appwidget.R;
+import android.appwidget.cts.R;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
diff --git a/tests/tests/assist/Android.mk b/tests/tests/assist/Android.mk
index 89d2c49..428ff7b 100644
--- a/tests/tests/assist/Android.mk
+++ b/tests/tests/assist/Android.mk
@@ -21,6 +21,11 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
 LOCAL_STATIC_JAVA_LIBRARIES := CtsAssistCommon ctstestrunner ctsdeviceutil
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/assist/AndroidTest.xml b/tests/tests/assist/AndroidTest.xml
index 329692d..f1af0c4 100644
--- a/tests/tests/assist/AndroidTest.xml
+++ b/tests/tests/assist/AndroidTest.xml
@@ -13,11 +13,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Test module config for Assist">
-    <include name="common-config" />
-    <option name="cts-apk-installer:test-file-name" value="CtsAssistService.apk" />
-    <option name="cts-apk-installer:test-file-name" value="CtsAssistApp.apk" />
-    <option name="run-command:run-command"
-         value="settings put secure voice_interaction_service android.assist.service/.MainInteractionService" />
-    <option name="cts-apk-installer:test-file-name" value="CtsAssistTestCases.apk" />
-</configuration>
+<configuration description="Config for CTS Assist test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAssistService.apk" />
+        <option name="test-file-name" value="CtsAssistApp.apk" />
+        <option name="test-file-name" value="CtsAssistTestCases.apk" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="settings put secure voice_interaction_service android.assist.service/.MainInteractionService" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.assist.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/assist/OldAndroidTest.xml b/tests/tests/assist/OldAndroidTest.xml
new file mode 100644
index 0000000..26db4cf
--- /dev/null
+++ b/tests/tests/assist/OldAndroidTest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Test module config for Assist">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsAssistService.apk" />
+    <option name="cts-apk-installer:test-file-name" value="CtsAssistApp.apk" />
+    <option name="run-command:run-command"
+         value="settings put secure voice_interaction_service android.assist.service/.MainInteractionService" />
+</configuration>
diff --git a/tests/tests/assist/service/Android.mk b/tests/tests/assist/service/Android.mk
index 07dc228..019b7d0 100644
--- a/tests/tests/assist/service/Android.mk
+++ b/tests/tests/assist/service/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_PACKAGE_NAME := CtsAssistService
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/assist/testapp/Android.mk b/tests/tests/assist/testapp/Android.mk
index 68297ef..6d066cba 100644
--- a/tests/tests/assist/testapp/Android.mk
+++ b/tests/tests/assist/testapp/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_PACKAGE_NAME := CtsAssistApp
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/bionic/Android.mk b/tests/tests/bionic/Android.mk
index 06b7920..db8c2a9 100644
--- a/tests/tests/bionic/Android.mk
+++ b/tests/tests/bionic/Android.mk
@@ -1,6 +1,6 @@
 LOCAL_PATH := $(call my-dir)
 
-test_executable := bionic-unit-tests-cts
+test_executable := CtsBionicTestCases
 list_executable := $(test_executable)_list
 
 include $(CLEAR_VARS)
@@ -26,6 +26,9 @@
     liblog \
     libgtest \
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_CTS_TEST_PACKAGE := android.bionic
 include $(BUILD_CTS_EXECUTABLE)
 
diff --git a/tests/tests/bionic/AndroidTest.xml b/tests/tests/bionic/AndroidTest.xml
new file mode 100644
index 0000000..97a9a0a
--- /dev/null
+++ b/tests/tests/bionic/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Bionic test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsBionicTestCases->/data/local/tmp/CtsBionicTestCases" />
+        <option name="append-bitness" value="true" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="CtsBionicTestCases" />
+        <option name="runtime-hint" value="1m10s" />
+    </test>
+</configuration>
diff --git a/tests/tests/bluetooth/Android.mk b/tests/tests/bluetooth/Android.mk
index 4f837fc..12a461c 100644
--- a/tests/tests/bluetooth/Android.mk
+++ b/tests/tests/bluetooth/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/bluetooth/AndroidManifest.xml b/tests/tests/bluetooth/AndroidManifest.xml
index 12838f3..3c751d7 100644
--- a/tests/tests/bluetooth/AndroidManifest.xml
+++ b/tests/tests/bluetooth/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.bluetooth">
+    package="android.bluetooth.cts">
 
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
@@ -28,7 +28,7 @@
 
     <!-- This is a self-instrumenting test package. -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.bluetooth"
+                     android:targetPackage="android.bluetooth.cts"
                      android:label="CTS tests of bluetooth component">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/bluetooth/AndroidTest.xml b/tests/tests/bluetooth/AndroidTest.xml
new file mode 100644
index 0000000..fb4b205
--- /dev/null
+++ b/tests/tests/bluetooth/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Bluetooth test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsBluetoothTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.bluetooth.cts" />
+        <option name="runtime-hint" value="1m11s" />
+    </test>
+</configuration>
diff --git a/tests/tests/calendarcommon/Android.mk b/tests/tests/calendarcommon/Android.mk
index fa4b6c5..ef019fc 100644
--- a/tests/tests/calendarcommon/Android.mk
+++ b/tests/tests/calendarcommon/Android.mk
@@ -31,4 +31,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/calendarcommon/AndroidManifest.xml b/tests/tests/calendarcommon/AndroidManifest.xml
index 17520a3..4f21b18 100644
--- a/tests/tests/calendarcommon/AndroidManifest.xml
+++ b/tests/tests/calendarcommon/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.calendarcommon2">
+    package="android.calendarcommon2.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -24,7 +24,7 @@
 
     <!-- This is a self-instrumenting test package. -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.calendarcommon2"
+                     android:targetPackage="android.calendarcommon2.cts"
                      android:label="CTS tests of calendarcommon">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/calendarcommon/AndroidTest.xml b/tests/tests/calendarcommon/AndroidTest.xml
new file mode 100644
index 0000000..65f2d7a
--- /dev/null
+++ b/tests/tests/calendarcommon/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Calendar test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsCalendarcommon2TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.calendarcommon2.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/calllog/Android.mk b/tests/tests/calllog/Android.mk
index 6a7e96a..99e1781 100644
--- a/tests/tests/calllog/Android.mk
+++ b/tests/tests/calllog/Android.mk
@@ -32,4 +32,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/calllog/AndroidManifest.xml b/tests/tests/calllog/AndroidManifest.xml
index 50fe115..d66559f 100644
--- a/tests/tests/calllog/AndroidManifest.xml
+++ b/tests/tests/calllog/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.calllog">
+        package="android.calllog.cts">
     <uses-sdk android:minSdkVersion="21" />
 
     <uses-permission android:name="android.permission.READ_CALL_LOG" />
@@ -29,7 +29,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.calllog"
+                     android:targetPackage="android.calllog.cts"
                      android:label="CTS tests for android.calllog package">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/calllog/AndroidTest.xml b/tests/tests/calllog/AndroidTest.xml
new file mode 100644
index 0000000..408aaac
--- /dev/null
+++ b/tests/tests/calllog/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Call Log test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsCallLogTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.calllog.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/content/Android.mk b/tests/tests/content/Android.mk
index 2c185d9..1c8fbfc 100644
--- a/tests/tests/content/Android.mk
+++ b/tests/tests/content/Android.mk
@@ -23,15 +23,21 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctsdeviceutil ctstestrunner
 
-# Resource unit tests use a private locale and some densities
-LOCAL_AAPT_FLAGS = -c xx_YY -c cs -c small -c normal -c large -c xlarge \
+# Resource unit tests use various locales (including a private locale) and some densities
+LOCAL_AAPT_FLAGS = -c small -c normal -c large -c xlarge \
         -c 320dpi -c 240dpi -c 160dpi -c 32dpi \
-        -c kok,kok_IN,kok_419,kok_419_VARIANT,kok_Knda_419,kok_Knda_419_VARIANT,kok_VARIANT,kok_Knda,tgl,tgl_PH
+        -c cs,fa_IR \
+        -c kok,kok_IN,kok_419,kok_419_VARIANT \
+        -c kok_Knda_419,kok_Knda_419_VARIANT,kok_VARIANT,kok_Knda \
+        -c tgl,tgl_PH,xx_YY
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsContentTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/content/AndroidManifest.xml b/tests/tests/content/AndroidManifest.xml
index bffb1f7..d88fdad 100644
--- a/tests/tests/content/AndroidManifest.xml
+++ b/tests/tests/content/AndroidManifest.xml
@@ -15,7 +15,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.content">
+    package="android.content.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <!-- content sync tests -->
@@ -35,7 +35,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
 
     <!-- Used for PackageManager test, don't delete this permission-tree -->
-    <permission-tree android:name="com.android.cts.content.permission.TEST_DYNAMIC"
+    <permission-tree android:name="android.content.cts.permission.TEST_DYNAMIC"
                     android:label="Test Tree"/>
 
     <!-- Used for PackageManager test, don't delete this permission-group -->
@@ -43,7 +43,7 @@
             android:label="@string/permlab_costMoney"
             android:description="@string/permdesc_costMoney"/>
 
-    <permission android:name="com.android.cts.content.CALL_ABROAD_PERMISSION"
+    <permission android:name="android.content.cts.CALL_ABROAD_PERMISSION"
                 android:label="@string/permlab_callAbroad"
                 android:description="@string/permdesc_callAbroad"
                 android:protectionLevel="normal"
@@ -75,16 +75,16 @@
             <meta-data android:name="android.app.intent.filter"
                 android:resource="@xml/intentfilter" />
             <intent-filter>
-                <action android:name="com.android.cts.content.action.TEST_ACTION" />
+                <action android:name="android.content.cts.action.TEST_ACTION" />
                 <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="com.android.cts.content.category.TEST_CATEGORY" />
+                <category android:name="android.content.cts.category.TEST_CATEGORY" />
             </intent-filter>
         </activity>
 
         <activity-alias android:name="android.content.cts.MockActivity2"
                 android:targetActivity="android.content.cts.MockActivity">
             <intent-filter>
-                <action android:name="com.android.cts.content.action.TEST_ACTION" />
+                <action android:name="android.content.cts.action.TEST_ACTION" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity-alias>
@@ -170,6 +170,13 @@
         <provider android:name="android.content.cts.MockRemoteContentProvider"
             android:authorities="remotectstest"
             android:process=":remoteprovider" android:multiprocess="false" />
+        <provider android:name="android.support.v4.content.FileProvider"
+            android:authorities="android.content.cts.fileprovider"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_paths" />
+        </provider>
 
         <service android:name="android.content.cts.MockService" />
 
@@ -194,7 +201,7 @@
 
         <activity android:name="android.content.cts.ClipboardManagerListenerActivity"/>
 
-        <activity android:name="com.android.cts.content.ImageCaptureActivity"
+        <activity android:name="android.content.cts.ImageCaptureActivity"
                   android:exported="true">
             <intent-filter>
                 <action android:name="android.media.action.IMAGE_CAPTURE" />
@@ -204,7 +211,7 @@
             </intent-filter>
         </activity>
 
-        <activity android:name="com.android.cts.content.ReadableFileReceiverActivity"
+        <activity android:name="android.content.cts.ReadableFileReceiverActivity"
                   android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.SEND" />
@@ -216,7 +223,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.content"
+                     android:targetPackage="android.content.cts"
                      android:label="CTS tests of android.content">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/content/AndroidTest.xml b/tests/tests/content/AndroidTest.xml
new file mode 100644
index 0000000..a8a8727
--- /dev/null
+++ b/tests/tests/content/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Content test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.WifiCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsContentTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.content.cts" />
+        <option name="runtime-hint" value="3m30s" />
+    </test>
+</configuration>
diff --git a/tests/tests/content/res/values-fa-rIR/strings.xml b/tests/tests/content/res/values-fa-rIR/strings.xml
new file mode 100644
index 0000000..25fd20c
--- /dev/null
+++ b/tests/tests/content/res/values-fa-rIR/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="am">صبح</string>
+</resources>
diff --git a/tests/tests/content/res/values-v24/strings.xml b/tests/tests/content/res/values-v24/strings.xml
new file mode 100644
index 0000000..b84c3a6
--- /dev/null
+++ b/tests/tests/content/res/values-v24/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+   <string name="version_cur">v24cur</string>
+</resources>
diff --git a/tests/tests/content/res/xml/alias.xml b/tests/tests/content/res/xml/alias.xml
index c245ba8..624b029 100644
--- a/tests/tests/content/res/xml/alias.xml
+++ b/tests/tests/content/res/xml/alias.xml
@@ -19,7 +19,7 @@
 
 <alias xmlns:android="http://schemas.android.com/apk/res/android">
     <intent android:action="android.intent.action.MAIN"
-        android:targetPackage="com.android.cts.content"
+        android:targetPackage="android.content.cts"
         android:targetClass="android.content.cts.ChildActivity"
         android:data="http://www.google.com/">
     </intent>
diff --git a/tests/tests/content/res/xml/file_paths.xml b/tests/tests/content/res/xml/file_paths.xml
new file mode 100644
index 0000000..e8d2861
--- /dev/null
+++ b/tests/tests/content/res/xml/file_paths.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 Google Inc. All Rights Reserved. -->
+
+<!-- Specify the storage area and path used in file provider. -->
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <files-path name="debug" path="debug/"/>
+</paths>
\ No newline at end of file
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsActivity.java b/tests/tests/content/src/android/content/cts/AvailableIntentsActivity.java
index 773defc..acd615c 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsActivity.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsActivity.java
@@ -16,7 +16,7 @@
 
 package android.content.cts;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java b/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
index 43d6cfe..588a915 100644
--- a/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
+++ b/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
@@ -49,15 +49,15 @@
     private static final String ACTION_BROADCAST_DISABLED =
             "android.content.cts.BroadcastReceiverTest.BROADCAST_DISABLED";
 
-    private static final long SEND_BROADCAST_TIMEOUT = 5000;
+    private static final long SEND_BROADCAST_TIMEOUT = 15000;
     private static final long START_SERVICE_TIMEOUT  = 3000;
 
     private static final ComponentName DISABLEABLE_RECEIVER =
-            new ComponentName("com.android.cts.content",
+            new ComponentName("android.content.cts",
                     "android.content.cts.MockReceiverDisableable");
 
     public BroadcastReceiverTest() {
-        super("com.android.cts.content", MockActivity.class);
+        super("android.content.cts", MockActivity.class);
     }
 
     @Override
@@ -166,7 +166,8 @@
         assertEquals(null, internalReceiver.getResultData());
         assertEquals(null, internalReceiver.getResultExtras(false));
 
-        activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL));
+        activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL)
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND));
         internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
 
         activity.unregisterReceiver(internalReceiver);
@@ -181,7 +182,8 @@
         map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
                 MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
         getInstrumentation().getContext().sendOrderedBroadcast(
-                new Intent(ACTION_BROADCAST_MOCKTEST), null, internalOrderReceiver,
+                new Intent(ACTION_BROADCAST_MOCKTEST).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+                null, internalOrderReceiver,
                 null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
         internalOrderReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
 
@@ -212,7 +214,8 @@
         // MockReceiverFirst --> MockReceiverAbort --> MockReceiver --> internalOrderReceiver.
         // And MockReceiver is the receiver which will be aborted.
         getInstrumentation().getContext().sendOrderedBroadcast(
-                new Intent(ACTION_BROADCAST_TESTABORT), null, internalOrderReceiver,
+                new Intent(ACTION_BROADCAST_TESTABORT).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+                null, internalOrderReceiver,
                 null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
         internalOrderReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
 
@@ -242,7 +245,8 @@
                 PackageManager.DONT_KILL_APP);
 
         context.sendOrderedBroadcast(
-                new Intent(ACTION_BROADCAST_DISABLED), null, lastReceiver,
+                new Intent(ACTION_BROADCAST_DISABLED).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+                null, lastReceiver,
                 null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, new Bundle());
         lastReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
 
@@ -257,7 +261,8 @@
         filter.addAction(ACTION_BROADCAST_INTERNAL);
         activity.registerReceiver(internalReceiver, filter);
 
-        activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL));
+        activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL)
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND));
         internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
         assertNull(internalReceiver.getIBinder());
 
@@ -267,7 +272,8 @@
         assertTrue(msc.waitForService(START_SERVICE_TIMEOUT));
 
         internalReceiver.reset();
-        activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL));
+        activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL)
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND));
         internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
         assertNotNull(internalReceiver.getIBinder());
         activity.unbindService(msc);
diff --git a/tests/tests/content/src/android/content/cts/ComponentNameTest.java b/tests/tests/content/src/android/content/cts/ComponentNameTest.java
index 6277bd6..23a2e00 100644
--- a/tests/tests/content/src/android/content/cts/ComponentNameTest.java
+++ b/tests/tests/content/src/android/content/cts/ComponentNameTest.java
@@ -85,14 +85,14 @@
     }
 
     public void testFlattenToString() {
-        assertEquals("com.android.cts.content/android.content.cts.ComponentNameTest",
+        assertEquals("android.content.cts/android.content.cts.ComponentNameTest",
                 getComponentName().flattenToString());
     }
 
     public void testGetShortClassName() {
         // set the expected value, test normal value
         String actual = getComponentName().getShortClassName();
-        assertEquals("android.content.cts.ComponentNameTest", actual);
+        assertEquals(".ComponentNameTest", actual);
 
         // Test class name which can be abbreviated
         ComponentName componentName = new ComponentName("com.android.view",
@@ -121,7 +121,7 @@
 
     public void testGetPackageName() {
         final String actual = getComponentName().getPackageName();
-        assertEquals("com.android.cts.content", actual);
+        assertEquals("android.content.cts", actual);
     }
 
     public void testUnflattenFromString() {
@@ -135,7 +135,7 @@
     public void testFlattenToShortString() {
         // Test normal
         String actual = getComponentName().flattenToShortString();
-        assertEquals("com.android.cts.content/android.content.cts.ComponentNameTest", actual);
+        assertEquals("android.content.cts/.ComponentNameTest", actual);
 
         // Test long class name
         final ComponentName componentName = new ComponentName("com.android.view",
@@ -152,12 +152,12 @@
         // new the ComponentName instances, both are the same.
         final ComponentName componentName1 = getComponentName();
         ComponentName componentName2 = new ComponentName(componentName1.getPackageName(),
-                componentName1.getShortClassName());
+                componentName1.getClassName());
         assertTrue(componentName1.equals(componentName2));
 
         // new the ComponentName instances, are not the same.
         componentName2 = new ComponentName(componentName1.getPackageName(),
-                componentName1.getShortClassName() + "different name");
+                componentName1.getClassName() + "different name");
         assertFalse(componentName1.equals(componentName2));
     }
 
@@ -168,7 +168,7 @@
     public void testToShortString() {
         // Test normal string
         final String shortString = getComponentName().toShortString();
-        assertEquals("{com.android.cts.content/android.content.cts.ComponentNameTest}", shortString);
+        assertEquals("{android.content.cts/android.content.cts.ComponentNameTest}", shortString);
     }
 
     public void testGetClassName() {
@@ -196,7 +196,7 @@
         ComponentName.writeToParcel(componentName, parcel);
         parcel.setDataPosition(0);
         assertFalse(0 == parcel.dataAvail());
-        assertEquals("com.android.cts.content", parcel.readString());
+        assertEquals("android.content.cts", parcel.readString());
         assertEquals("android.content.cts.ComponentNameTest", parcel.readString());
 
         // Test null data
diff --git a/tests/tests/content/src/android/content/cts/ContentProviderTest.java b/tests/tests/content/src/android/content/cts/ContentProviderTest.java
index 5fee379..e7d8a05 100644
--- a/tests/tests/content/src/android/content/cts/ContentProviderTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentProviderTest.java
@@ -27,7 +27,7 @@
 import android.os.ParcelFileDescriptor;
 import android.test.AndroidTestCase;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -37,7 +37,7 @@
  * Test {@link ContentProvider}.
  */
 public class ContentProviderTest extends AndroidTestCase {
-    private static final String TEST_PACKAGE_NAME = "com.android.cts.content";
+    private static final String TEST_PACKAGE_NAME = "android.content.cts";
     private static final String TEST_FILE_NAME = "testFile.tmp";
     private static final String TEST_DB_NAME = "test.db";
 
diff --git a/tests/tests/content/src/android/content/cts/ContentResolverTest.java b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
index 628f956..ea1227c 100644
--- a/tests/tests/content/src/android/content/cts/ContentResolverTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
@@ -16,7 +16,7 @@
 
 package android.content.cts;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 
 import android.accounts.Account;
@@ -80,7 +80,7 @@
     private static final int VALUE2 = 2;
     private static final int VALUE3 = 3;
 
-    private static final String TEST_PACKAGE_NAME = "com.android.cts.content";
+    private static final String TEST_PACKAGE_NAME = "android.content.cts";
 
     private Context mContext;
     private ContentResolver mContentResolver;
diff --git a/tests/tests/content/src/android/content/cts/ContextTest.java b/tests/tests/content/src/android/content/cts/ContextTest.java
index d77c1b1..cf27bda 100644
--- a/tests/tests/content/src/android/content/cts/ContextTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextTest.java
@@ -16,7 +16,7 @@
 
 package android.content.cts;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 import org.xmlpull.v1.XmlPullParserException;
 
diff --git a/tests/tests/content/src/android/content/cts/ContextWrapperCtsActivity.java b/tests/tests/content/src/android/content/cts/ContextWrapperCtsActivity.java
index 9ff4df9..7ea2ab7 100644
--- a/tests/tests/content/src/android/content/cts/ContextWrapperCtsActivity.java
+++ b/tests/tests/content/src/android/content/cts/ContextWrapperCtsActivity.java
@@ -21,7 +21,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 public class ContextWrapperCtsActivity extends Activity {
     @Override
diff --git a/tests/tests/content/src/android/content/cts/ContextWrapperTest.java b/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
index edc9538..28e248e 100644
--- a/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
@@ -16,7 +16,7 @@
 
 package android.content.cts;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -477,7 +477,7 @@
     }
 
     public void testGetPackageName() {
-        assertEquals("com.android.cts.content", mContextWrapper.getPackageName());
+        assertEquals("android.content.cts", mContextWrapper.getPackageName());
     }
 
     public void testGetCacheDir() {
diff --git a/tests/tests/content/src/android/content/cts/ImageCaptureActivity.java b/tests/tests/content/src/android/content/cts/ImageCaptureActivity.java
index 71bf250..d8ba494 100644
--- a/tests/tests/content/src/android/content/cts/ImageCaptureActivity.java
+++ b/tests/tests/content/src/android/content/cts/ImageCaptureActivity.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.content;
+package android.content.cts;
 
 import android.app.Activity;
 import android.content.ClipData;
@@ -30,7 +30,7 @@
 import java.io.Writer;
 
 public class ImageCaptureActivity extends Activity {
-    public static final String ACTION_FILE_READY = "com.android.cts.content.action.file_ready";
+    public static final String ACTION_FILE_READY = "android.content.cts.action.file_ready";
     private static final String TAG = ImageCaptureUriExtraToClipDataTest.TAG;
 
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/tests/tests/content/src/android/content/cts/ImageCaptureUriExtraToClipDataTest.java b/tests/tests/content/src/android/content/cts/ImageCaptureUriExtraToClipDataTest.java
index bb2a43d..b2a90f2 100644
--- a/tests/tests/content/src/android/content/cts/ImageCaptureUriExtraToClipDataTest.java
+++ b/tests/tests/content/src/android/content/cts/ImageCaptureUriExtraToClipDataTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.content;
+package android.content.cts;
 
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -87,8 +87,8 @@
 
     private void startActivityWithAction(String action) {
         Intent intent = new Intent(action);
-        intent.setComponent(new ComponentName("com.android.cts.content",
-                        "com.android.cts.content.ImageCaptureActivity"));
+        intent.setComponent(new ComponentName("android.content.cts",
+                        "android.content.cts.ImageCaptureActivity"));
         intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTestFile));
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         getContext().startActivity(intent);
diff --git a/tests/tests/content/src/android/content/cts/IntentTest.java b/tests/tests/content/src/android/content/cts/IntentTest.java
index 677b31f..65da548 100644
--- a/tests/tests/content/src/android/content/cts/IntentTest.java
+++ b/tests/tests/content/src/android/content/cts/IntentTest.java
@@ -720,33 +720,33 @@
     }
 
     public void testResolveActivitySingleMatch() {
-        final Intent intent = new Intent("com.android.cts.content.action.TEST_ACTION");
-        intent.addCategory("com.android.cts.content.category.TEST_CATEGORY");
+        final Intent intent = new Intent("android.content.cts.action.TEST_ACTION");
+        intent.addCategory("android.content.cts.category.TEST_CATEGORY");
 
         // Should only have one activity responding to narrow category
         final ComponentName target = intent.resolveActivity(mPm);
-        assertEquals("com.android.cts.content", target.getPackageName());
+        assertEquals("android.content.cts", target.getPackageName());
         assertEquals("android.content.cts.MockActivity", target.getClassName());
     }
 
     public void testResolveActivityShortcutMatch() {
-        final Intent intent = new Intent("com.android.cts.content.action.TEST_ACTION");
+        final Intent intent = new Intent("android.content.cts.action.TEST_ACTION");
         intent.setComponent(
-                new ComponentName("com.android.cts.content", "android.content.cts.MockActivity2"));
+                new ComponentName("android.content.cts", "android.content.cts.MockActivity2"));
 
         // Multiple activities match, but we asked for explicit component
         final ComponentName target = intent.resolveActivity(mPm);
-        assertEquals("com.android.cts.content", target.getPackageName());
+        assertEquals("android.content.cts", target.getPackageName());
         assertEquals("android.content.cts.MockActivity2", target.getClassName());
     }
 
     public void testResolveActivityMultipleMatch() {
-        final Intent intent = new Intent("com.android.cts.content.action.TEST_ACTION");
+        final Intent intent = new Intent("android.content.cts.action.TEST_ACTION");
 
         // Should have multiple activities, resulting in resolver dialog
         final ComponentName target = intent.resolveActivity(mPm);
         final String pkgName = target.getPackageName();
-        assertFalse("com.android.cts.content".equals(pkgName));
+        assertFalse("android.content.cts".equals(pkgName));
 
         // Whoever they are must be able to set preferred activities
         if (!"android".equals(pkgName)) {
diff --git a/tests/tests/content/src/android/content/cts/Intent_ShortcutIconResourceTest.java b/tests/tests/content/src/android/content/cts/Intent_ShortcutIconResourceTest.java
index 062ef90..ce45f1c 100644
--- a/tests/tests/content/src/android/content/cts/Intent_ShortcutIconResourceTest.java
+++ b/tests/tests/content/src/android/content/cts/Intent_ShortcutIconResourceTest.java
@@ -29,7 +29,7 @@
 
     ShortcutIconResource mShortcutIconResource;
     Context mContext;
-    final int resourceId = com.android.cts.content.R.string.notify;
+    final int resourceId = android.content.cts.R.string.notify;
 
     @Override
     protected void setUp() throws Exception {
@@ -63,7 +63,7 @@
     public void testWriteToParcel() {
 
         mShortcutIconResource = ShortcutIconResource.fromContext(mContext,
-                com.android.cts.content.R.string.notify);
+                android.content.cts.R.string.notify);
         assertNotNull(mShortcutIconResource);
         Parcel parce = Parcel.obtain();
         mShortcutIconResource.writeToParcel(parce, 1);
diff --git a/tests/tests/content/src/android/content/cts/ReadableFileReceiverActivity.java b/tests/tests/content/src/android/content/cts/ReadableFileReceiverActivity.java
index bab516e..d5a8b72 100644
--- a/tests/tests/content/src/android/content/cts/ReadableFileReceiverActivity.java
+++ b/tests/tests/content/src/android/content/cts/ReadableFileReceiverActivity.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.content;
+package android.content.cts;
 
 import android.app.Activity;
 import android.content.ClipData;
@@ -32,7 +32,7 @@
 
 public class ReadableFileReceiverActivity extends Activity {
     public static final String ACTION_CONFIRM_READ_SUCCESS
-        = "com.android.cts.content.action.CONFIRM_READ_SUCCESS";
+        = "android.content.cts.action.CONFIRM_READ_SUCCESS";
     private static final String TAG = ReadableUriExtraToClipDataTest.TAG;
 
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/tests/tests/content/src/android/content/cts/ReadableUriExtraToClipDataTest.java b/tests/tests/content/src/android/content/cts/ReadableUriExtraToClipDataTest.java
index 129d964..8b89497 100644
--- a/tests/tests/content/src/android/content/cts/ReadableUriExtraToClipDataTest.java
+++ b/tests/tests/content/src/android/content/cts/ReadableUriExtraToClipDataTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.content;
+package android.content.cts;
 
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
diff --git a/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java b/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java
index c271483..b4fcb31 100644
--- a/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java
+++ b/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java
@@ -18,8 +18,9 @@
 
 import android.app.QueuedWork;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.os.StrictMode;
 import android.preference.PreferenceManager;
 import android.test.AndroidTestCase;
@@ -39,7 +40,6 @@
     private static final String TAG = "SharedPreferencesTest";
 
     private Context mContext;
-    private ContextWrapper mContextWrapper;
 
     private File mPrefsFile;
 
@@ -47,15 +47,17 @@
     protected void setUp() throws Exception {
         super.setUp();
         mContext = getContext();
-        mContextWrapper = new ContextWrapper(mContext);
 
         SharedPreferences prefs = getPrefs();
         prefs.edit().clear().commit();
-
-        // Duplicated from ContextImpl.java.  Not ideal, but there wasn't a better
-        // way to reach into Context{Wrapper,Impl} to ask where this file lives.
-        mPrefsFile = new File("/data/data/com.android.cts.content/shared_prefs",
-                              "com.android.cts.content_preferences.xml");
+        try {
+            ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(
+                    mContext.getPackageName(), 0);
+            mPrefsFile = new File(applicationInfo.dataDir,
+                    "shared_prefs/android.content.cts_preferences.xml");
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalStateException(e);
+        }
         mPrefsFile.delete();
     }
 
diff --git a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
index 1e9f5a2..6a06eb8 100644
--- a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
@@ -16,7 +16,7 @@
 
 package android.content.pm.cts;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 
 import android.content.pm.ApplicationInfo;
diff --git a/tests/tests/content/src/android/content/pm/cts/ApplicationInfo_DisplayNameComparatorTest.java b/tests/tests/content/src/android/content/pm/cts/ApplicationInfo_DisplayNameComparatorTest.java
index 211a2ca..713c60b 100644
--- a/tests/tests/content/src/android/content/pm/cts/ApplicationInfo_DisplayNameComparatorTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ApplicationInfo_DisplayNameComparatorTest.java
@@ -26,7 +26,7 @@
  * Test {@link DisplayNameComparator}.
  */
 public class ApplicationInfo_DisplayNameComparatorTest extends AndroidTestCase {
-    private static final String PACKAGE_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
     DisplayNameComparator mDisplayNameComparator;
 
     @Override
diff --git a/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
index 14a42c01..e11beec 100644
--- a/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
@@ -28,14 +28,14 @@
 import android.util.Printer;
 import android.util.StringBuilderPrinter;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 
 /**
  * Test {@link ComponentInfo}.
  */
 public class ComponentInfoTest extends AndroidTestCase {
-    private final String PACKAGE_NAME = "com.android.cts.content";
+    private final String PACKAGE_NAME = "android.content.cts";
     private ComponentInfo mComponentInfo;
 
     public void testConstructor() {
diff --git a/tests/tests/content/src/android/content/pm/cts/InstrumentationInfoTest.java b/tests/tests/content/src/android/content/pm/cts/InstrumentationInfoTest.java
index 5b7747d..ed9366b 100644
--- a/tests/tests/content/src/android/content/pm/cts/InstrumentationInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/InstrumentationInfoTest.java
@@ -25,7 +25,7 @@
 import android.test.AndroidTestCase;
 
 public class InstrumentationInfoTest extends AndroidTestCase {
-    private static final String PACKAGE_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
     private static final String INSTRUMENTATION_NAME =
             "android.content.pm.cts.TestPmInstrumentation";
 
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java b/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java
index 0540e0b..886b4f5 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java
@@ -32,7 +32,7 @@
     private PackageManager mPackageManager;
     private PackageInfo mPackageInfo;
     private PackageInfo mPackageInfoCmp;
-    private static final String PACKAGE_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
 
     @Override
     protected void setUp() throws Exception {
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageItemInfoTest.java b/tests/tests/content/src/android/content/pm/cts/PackageItemInfoTest.java
index 53e69da..48db1b8 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageItemInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageItemInfoTest.java
@@ -16,7 +16,7 @@
 
 package android.content.pm.cts;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 
 import android.content.ComponentName;
@@ -30,7 +30,7 @@
 import android.util.Printer;
 
 public class PackageItemInfoTest extends AndroidTestCase {
-    private static final String PACKAGE_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
     private static final String ACTIVITY_NAME = "android.content.pm.cts.TestPmActivity";
     private static final String METADATA_NAME = "android.content.pm.cts.xmltest";
     private PackageManager mPackageManager;
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageItemInfo_DisplayNameComparatorTest.java b/tests/tests/content/src/android/content/pm/cts/PackageItemInfo_DisplayNameComparatorTest.java
index 0cfd1dd..4624c85 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageItemInfo_DisplayNameComparatorTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageItemInfo_DisplayNameComparatorTest.java
@@ -26,7 +26,7 @@
 import android.test.AndroidTestCase;
 
 public class PackageItemInfo_DisplayNameComparatorTest extends AndroidTestCase {
-    private static final String PACKAGE_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
     private static final String ACTIVITY_NAME = "android.content.pm.cts.TestPmActivity";
     private static final String CMPACTIVITY_NAME = "android.content.pm.cts.TestPmCompare";
 
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
index cb3de2a..490da35e 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -16,7 +16,7 @@
 
 package android.content.pm.cts;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 
 import android.content.ComponentName;
@@ -44,8 +44,8 @@
  */
 public class PackageManagerTest extends AndroidTestCase {
     private PackageManager mPackageManager;
-    private static final String PACKAGE_NAME = "com.android.cts.content";
-    private static final String CONTENT_PKG_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
+    private static final String CONTENT_PKG_NAME = "android.content.cts";
     private static final String ACTIVITY_ACTION_NAME = "android.intent.action.PMTEST";
     private static final String MAIN_ACTION_NAME = "android.intent.action.MAIN";
     private static final String SERVICE_ACTION_NAME =
@@ -110,7 +110,7 @@
         String testPermissionsGroup = "android.permission-group.COST_MONEY";
         List<PermissionInfo> permissions = mPackageManager.queryPermissionsByGroup(
                 testPermissionsGroup, PackageManager.GET_META_DATA);
-        checkPermissionInfoName("com.android.cts.content.CALL_ABROAD_PERMISSION", permissions);
+        checkPermissionInfoName("android.content.cts.CALL_ABROAD_PERMISSION", permissions);
 
         ApplicationInfo appInfo = mPackageManager.getApplicationInfo(PACKAGE_NAME, 0);
         List<ProviderInfo> providers = mPackageManager.queryContentProviders(PACKAGE_NAME,
@@ -390,7 +390,7 @@
 
     public void testOpPermission() {
         PermissionInfo permissionInfo = new PermissionInfo();
-        String permissionName = "com.android.cts.content.permission.TEST_DYNAMIC.ADD";
+        String permissionName = "android.content.cts.permission.TEST_DYNAMIC.ADD";
         permissionInfo.name = permissionName;
         permissionInfo.labelRes = R.string.permlab_testDynamic;
         permissionInfo.nonLocalizedLabel = "Test Tree";
@@ -445,7 +445,7 @@
     public void testGetResources() throws NameNotFoundException {
         ComponentName componentName = new ComponentName(PACKAGE_NAME, ACTIVITY_NAME);
         int resourceId = R.xml.pm_test;
-        String xmlName = "com.android.cts.content:xml/pm_test";
+        String xmlName = "android.content.cts:xml/pm_test";
         ApplicationInfo appInfo = mPackageManager.getApplicationInfo(PACKAGE_NAME, 0);
         assertNotNull(mPackageManager.getXml(PACKAGE_NAME, resourceId, appInfo));
         assertEquals(xmlName, mPackageManager.getResourcesForActivity(componentName)
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageStatsTest.java b/tests/tests/content/src/android/content/pm/cts/PackageStatsTest.java
index 6425209..722175b 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageStatsTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageStatsTest.java
@@ -22,7 +22,7 @@
 import android.test.AndroidTestCase;
 
 public class PackageStatsTest extends AndroidTestCase {
-    private static final String PACKAGE_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
 
     public void testPackageStats() {
         // Set mock data to make sure the functionality of constructor
diff --git a/tests/tests/content/src/android/content/pm/cts/ProviderInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ProviderInfoTest.java
index 6256a69..4e07312 100644
--- a/tests/tests/content/src/android/content/pm/cts/ProviderInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ProviderInfoTest.java
@@ -21,14 +21,17 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.XmlResourceParser;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
 
+import libcore.io.IoUtils;
+
 import java.util.Iterator;
 import java.util.List;
 
 public class ProviderInfoTest extends AndroidTestCase {
-    private static final String PACKAGE_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
     private static final String PROVIDER_NAME = "android.content.cts.MockContentProvider";
 
     public void testProviderInfo() throws NameNotFoundException {
@@ -50,6 +53,19 @@
         }
     }
 
+    public void testProviderMetaData() {
+        final ProviderInfo info = getContext().getPackageManager()
+                .resolveContentProvider("android.content.cts.fileprovider",
+                        PackageManager.GET_META_DATA);
+        final XmlResourceParser in = info.loadXmlMetaData(
+                getContext().getPackageManager(), "android.support.FILE_PROVIDER_PATHS");
+        try {
+            assertNotNull(in);
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
     private void checkProviderInfoMethods(ProviderInfo providerInfo, Parcel p) {
         // Test toString, describeContents
         assertNotNull(providerInfo.toString());
diff --git a/tests/tests/content/src/android/content/pm/cts/ResolveInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ResolveInfoTest.java
index af3f161..9b149f5 100644
--- a/tests/tests/content/src/android/content/pm/cts/ResolveInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ResolveInfoTest.java
@@ -26,7 +26,7 @@
 import android.util.Printer;
 
 public class ResolveInfoTest extends AndroidTestCase {
-    private static final String PACKAGE_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
     private static final String MAIN_ACTION_NAME = "android.intent.action.MAIN";
     private static final String ACTIVITY_NAME = "android.content.pm.cts.TestPmActivity";
     private static final String SERVICE_NAME = "android.content.pm.cts.activity.PMTEST_SERVICE";
diff --git a/tests/tests/content/src/android/content/pm/cts/ServiceInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ServiceInfoTest.java
index 297ab69..4298586 100644
--- a/tests/tests/content/src/android/content/pm/cts/ServiceInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ServiceInfoTest.java
@@ -25,7 +25,7 @@
 import android.test.AndroidTestCase;
 
 public class ServiceInfoTest extends AndroidTestCase {
-    private static final String PACKAGE_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
     private static final String SERVICE_NAME = "android.content.pm.cts.TestPmService";
 
     public void testServiceInfo() throws NameNotFoundException {
diff --git a/tests/tests/content/src/android/content/res/cts/ArrayTest.java b/tests/tests/content/src/android/content/res/cts/ArrayTest.java
index 909fbf6..7ac1133 100644
--- a/tests/tests/content/src/android/content/res/cts/ArrayTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ArrayTest.java
@@ -20,7 +20,7 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 public class ArrayTest extends AndroidTestCase {
     private Resources mResources;
diff --git a/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java b/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java
index e8d363b..21a8682 100644
--- a/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java
+++ b/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java
@@ -15,7 +15,7 @@
  */
 package android.content.res.cts;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/tests/tests/content/src/android/content/res/cts/ColorStateListTest.java b/tests/tests/content/src/android/content/res/cts/ColorStateListTest.java
index 88f5798..2222ce4 100644
--- a/tests/tests/content/src/android/content/res/cts/ColorStateListTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ColorStateListTest.java
@@ -27,7 +27,7 @@
 import android.os.Parcel;
 import android.test.AndroidTestCase;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 
 public class ColorStateListTest extends AndroidTestCase {
diff --git a/tests/tests/content/src/android/content/res/cts/ConfigTest.java b/tests/tests/content/src/android/content/res/cts/ConfigTest.java
index 0b94b6f..2390146 100644
--- a/tests/tests/content/src/android/content/res/cts/ConfigTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ConfigTest.java
@@ -31,7 +31,7 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 public class ConfigTest extends AndroidTestCase {
     enum Properties {
diff --git a/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java b/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
index 30c78a8..c1ee6c4 100644
--- a/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
@@ -22,6 +22,7 @@
 import android.content.res.Configuration;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
+import android.util.LocaleList;
 import android.view.View;
 
 public class ConfigurationTest extends AndroidTestCase {
@@ -40,7 +41,7 @@
         mConfig = new Configuration();
         mConfig.fontScale = 2;
         mConfig.mcc = mConfig.mnc = 1;
-        mConfig.locale = Locale.getDefault();
+        mConfig.setLocale(Locale.getDefault());
         mConfig.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
         mConfig.keyboard = Configuration.KEYBOARD_NOKEYS;
         mConfig.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
@@ -93,6 +94,27 @@
         cfg2.touchscreen = 2;
         assertEquals(1, cfg1.compareTo(cfg2));
 
+        cfg1.setLocales(LocaleList.forLanguageTags("fr"));
+        cfg2.setLocales(LocaleList.forLanguageTags("fr,en"));
+        assertTrue(cfg1.compareTo(cfg2) < 0);
+        cfg1.setLocales(LocaleList.forLanguageTags("fr,en"));
+        cfg2.setLocales(LocaleList.forLanguageTags("fr"));
+        assertTrue(cfg1.compareTo(cfg2) > 0);
+
+        cfg1.setLocales(LocaleList.forLanguageTags("fr,en"));
+        cfg2.setLocales(LocaleList.forLanguageTags("fr,en-US"));
+        assertTrue(cfg1.compareTo(cfg2) < 0);
+        cfg1.setLocales(LocaleList.forLanguageTags("fr,en-US"));
+        cfg2.setLocales(LocaleList.forLanguageTags("fr,en"));
+        assertTrue(cfg1.compareTo(cfg2) > 0);
+
+        cfg1.locale = Locale.forLanguageTag("en");
+        cfg2.locale = Locale.forLanguageTag("en-Shaw");
+        assertTrue(cfg1.compareTo(cfg2) < 0);
+        cfg1.locale = Locale.forLanguageTag("en-Shaw");
+        cfg2.locale = Locale.forLanguageTag("en");
+        assertTrue(cfg1.compareTo(cfg2) > 0);
+
         cfg1.locale = new Locale("", "", "2");
         cfg2.locale = new Locale("", "", "3");
         assertEquals(-1, cfg1.compareTo(cfg2));
@@ -114,6 +136,13 @@
         cfg2.locale = new Locale("2", "", "");
         assertEquals(1, cfg1.compareTo(cfg2));
 
+        cfg1.locale = new Locale("");
+        cfg2.locale = null;
+        assertTrue(cfg1.compareTo(cfg2) < 0);
+        cfg1.locale = null;
+        cfg2.locale = new Locale("");
+        assertTrue(cfg1.compareTo(cfg2) > 0);
+
         cfg1.mnc = 2;
         cfg2.mnc = 3;
         assertEquals(-1, cfg1.compareTo(cfg2));
@@ -160,6 +189,11 @@
                 | ActivityInfo.CONFIG_MNC
                 | ActivityInfo.CONFIG_LOCALE
                 | ActivityInfo.CONFIG_LAYOUT_DIRECTION, mConfigDefault, config);
+        config.setLocales(LocaleList.forLanguageTags("fr,en"));
+        doConfigCompare(ActivityInfo.CONFIG_MCC
+                | ActivityInfo.CONFIG_MNC
+                | ActivityInfo.CONFIG_LOCALE
+                | ActivityInfo.CONFIG_LAYOUT_DIRECTION, mConfigDefault, config);
         config.screenLayout = 1;
         doConfigCompare(ActivityInfo.CONFIG_MCC
                 | ActivityInfo.CONFIG_MNC
@@ -282,6 +316,7 @@
         assertFalse(temp.equals(mConfigDefault));
         temp.setToDefaults();
         assertTrue(temp.equals(mConfigDefault));
+        assertTrue(temp.getLocales().isEmpty());
     }
 
     public void testToString() {
@@ -289,47 +324,62 @@
     }
 
     public void testWriteToParcel() {
-        assertWriteToParcel(createConfig(null), Parcel.obtain());
+        assertWriteToParcel(createConfig((Locale) null), Parcel.obtain());
+        assertWriteToParcel(createConfig(new Locale("")), Parcel.obtain());
         assertWriteToParcel(createConfig(Locale.JAPAN), Parcel.obtain());
+        assertWriteToParcel(createConfig(Locale.forLanguageTag("en-Shaw")), Parcel.obtain());
+        assertWriteToParcel(createConfig(LocaleList.forLanguageTags("fr,en-US")), Parcel.obtain());
     }
 
     public void testSetLocale() {
         Configuration config = new Configuration();
 
+        config.setLocale(null);
+        assertNull(config.locale);
+        assertTrue(config.getLocales().isEmpty());
+
         config.setLocale(Locale.getDefault());
         assertEquals(Locale.getDefault(), config.locale);
-        assertEquals(View.LAYOUT_DIRECTION_LTR, config.getLayoutDirection());
+        assertEquals(new LocaleList(Locale.getDefault()), config.getLocales());
 
         config.setLocale(Locale.ENGLISH);
         assertEquals(Locale.ENGLISH, config.locale);
+        assertEquals(new LocaleList(Locale.ENGLISH), config.getLocales());
         assertEquals(View.LAYOUT_DIRECTION_LTR, config.getLayoutDirection());
 
         config.setLocale(Locale.US);
         assertEquals(Locale.US, config.locale);
+        assertEquals(new LocaleList(Locale.US), config.getLocales());
         assertEquals(View.LAYOUT_DIRECTION_LTR, config.getLayoutDirection());
 
         final Locale arEGLocale = new Locale("ar", "EG");
         config.setLocale(arEGLocale);
         assertEquals(arEGLocale, config.locale);
+        assertEquals(new LocaleList(arEGLocale), config.getLocales());
         assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
 
-        final Locale faFALocale = new Locale("fa", "FA");
-        config.setLocale(faFALocale);
-        assertEquals(faFALocale, config.locale);
+        final Locale faIRLocale = new Locale("fa", "IR");
+        config.setLocale(faIRLocale);
+        assertEquals(faIRLocale, config.locale);
+        assertEquals(new LocaleList(faIRLocale), config.getLocales());
         assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
 
         final Locale iwILLocale = new Locale("iw", "IL");
         config.setLocale(iwILLocale);
         assertEquals(iwILLocale, config.locale);
+        assertEquals(new LocaleList(iwILLocale), config.getLocales());
+        assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
+
+        final Locale urPKLocale = new Locale("ur", "PK");
+        config.setLocale(urPKLocale);
+        assertEquals(urPKLocale, config.locale);
+        assertEquals(new LocaleList(urPKLocale), config.getLocales());
         assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
     }
 
     public void testSetGetLayoutDirection() {
         Configuration config = new Configuration();
 
-        config.setLayoutDirection(Locale.getDefault());
-        assertEquals(View.LAYOUT_DIRECTION_LTR, config.getLayoutDirection());
-
         config.setLayoutDirection(Locale.ENGLISH);
         assertEquals(View.LAYOUT_DIRECTION_LTR, config.getLayoutDirection());
 
@@ -340,21 +390,240 @@
         config.setLayoutDirection(arEGLocale);
         assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
 
-        final Locale faFALocale = new Locale("fa", "FA");
-        config.setLayoutDirection(faFALocale);
+        final Locale faIRLocale = new Locale("fa", "IR");
+        config.setLayoutDirection(faIRLocale);
         assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
 
         final Locale iwILLocale = new Locale("iw", "IL");
         config.setLayoutDirection(iwILLocale);
         assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
+
+        final Locale urPKLocale = new Locale("ur", "PK");
+        config.setLayoutDirection(urPKLocale);
+        assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
+    }
+
+    public void testFixUpLocaleList() {
+        Configuration config = new Configuration();
+
+        config.setLocales(LocaleList.forLanguageTags("fr"));
+        config.locale = null;
+        assertEquals(LocaleList.getEmptyLocaleList(), config.getLocales());
+
+        config.setLocales(LocaleList.forLanguageTags("fr,en"));
+        config.locale = Locale.forLanguageTag("en");
+        assertEquals(LocaleList.forLanguageTags("en"), config.getLocales());
+
+        config.setLocales(LocaleList.forLanguageTags("fr,en"));
+        config.locale = Locale.forLanguageTag("fr");
+        assertEquals(LocaleList.forLanguageTags("fr,en"), config.getLocales());
+    }
+
+    public void testSetTo_nullLocale() {
+        Configuration config1 = new Configuration();
+        Configuration config2 = new Configuration();
+        assertEquals(null, config2.locale);
+
+        config1.setLocale(Locale.FRENCH);
+        config1.setTo(config2);
+        assertEquals(null, config1.locale);
+    }
+
+    public void testSetTo_localeFixUp() {
+        Configuration config1 = new Configuration();
+        Configuration config2 = new Configuration();
+        config2.locale = Locale.FRENCH;
+
+        config1.setTo(config2);
+        assertEquals(Locale.FRENCH, config1.locale);
+        assertEquals(new LocaleList(Locale.FRENCH), config1.getLocales());
+        assertEquals(new LocaleList(Locale.FRENCH), config2.getLocales());
+    }
+
+    public void testToString_localeFixUp() {
+        Configuration config1 = new Configuration();
+        Configuration config2 = new Configuration();
+        config1.setLocales(LocaleList.forLanguageTags("fr,en"));
+        config1.locale = Locale.forLanguageTag("en");
+        config2.setLocales(LocaleList.forLanguageTags("en"));
+
+        assertEquals(config1.toString(), config2.toString());
+    }
+
+    public void testUpdateFrom_localeFixUp() {
+        Configuration config1, config2;
+        int changed;
+
+        config1 = new Configuration();
+        config2 = new Configuration();
+        config1.locale = Locale.FRENCH;
+        changed = config1.updateFrom(config2);
+        assertEquals(0, changed);
+        assertEquals(Locale.FRENCH, config1.locale);
+        assertEquals(new LocaleList(Locale.FRENCH), config1.getLocales());
+
+        config1 = new Configuration();
+        config2 = new Configuration();
+        config2.locale = Locale.FRENCH;
+        changed = config1.updateFrom(config2);
+        assertEquals(ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_LAYOUT_DIRECTION, changed);
+        assertEquals(Locale.FRENCH, config1.locale);
+        assertEquals(new LocaleList(Locale.FRENCH), config1.getLocales());
+        assertEquals(new LocaleList(Locale.FRENCH), config2.getLocales());
+
+        config1 = new Configuration();
+        config2 = new Configuration();
+        config1.setLocales(LocaleList.forLanguageTags("en,fr"));
+        config1.locale = Locale.forLanguageTag("fr");
+        config2.setLocales(LocaleList.forLanguageTags("en,de"));
+        config2.locale = Locale.forLanguageTag("fr");
+        changed = config1.updateFrom(config2);
+        assertEquals(0, changed);
+        assertEquals(Locale.forLanguageTag("fr"), config1.locale);
+        assertEquals(LocaleList.forLanguageTags("fr"), config1.getLocales());
+        assertEquals(LocaleList.forLanguageTags("fr"), config2.getLocales());
+    }
+
+    public void testUpdateFrom_layoutDirection() {
+        Configuration config1, config2;
+        int changed;
+
+        config1 = new Configuration();
+        config2 = new Configuration();
+        config1.setLocales(LocaleList.forLanguageTags("fr,en"));
+        config2.setLocales(LocaleList.forLanguageTags("de,en"));
+        changed = config1.updateFrom(config2);
+        assertTrue((changed & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0);
+
+        config1 = new Configuration();
+        config2 = new Configuration();
+        config1.setLocales(LocaleList.forLanguageTags("fr,en"));
+        config2.setLocales(LocaleList.forLanguageTags("fr,de"));
+        changed = config1.updateFrom(config2);
+        assertEquals(0, changed & ActivityInfo.CONFIG_LAYOUT_DIRECTION);
+    }
+
+    public void testDiff_localeFixUp() {
+        Configuration config1 = new Configuration();
+        Configuration config2 = new Configuration();
+        config1.setLocales(LocaleList.forLanguageTags("en,fr"));
+        config1.locale = Locale.forLanguageTag("fr");
+        config2.setLocales(LocaleList.forLanguageTags("en,de"));
+        config2.locale = Locale.forLanguageTag("fr");
+
+        int diff = config1.diff(config2);
+        assertEquals(0, diff);
+    }
+
+    public void testCompareTo_localeFixUp() {
+        Configuration config1 = new Configuration();
+        Configuration config2 = new Configuration();
+        config1.setLocales(LocaleList.forLanguageTags("en,fr"));
+        config2.setLocales(LocaleList.forLanguageTags("en,fr"));
+        assertEquals(0, config1.compareTo(config2));
+        config1.locale = new Locale("2");
+        config2.locale = new Locale("3");
+        assertEquals(-1, config1.compareTo(config2));
+    }
+
+    public void testSetLocales_null() {
+        Configuration config = new Configuration();
+        config.setLocales(null);
+        assertNull(config.locale);
+        assertNotNull(config.getLocales());
+        assertTrue(config.getLocales().isEmpty());
+        assertEquals(View.LAYOUT_DIRECTION_LTR, config.getLayoutDirection());
+    }
+
+    public void testSetLocales_emptyList() {
+        Configuration config = new Configuration();
+        config.setLocales(LocaleList.getEmptyLocaleList());
+        assertNull(config.locale);
+        assertNotNull(config.getLocales());
+        assertTrue(config.getLocales().isEmpty());
+        assertEquals(View.LAYOUT_DIRECTION_LTR, config.getLayoutDirection());
+    }
+
+    public void testSetLocales_oneLtr() {
+        Configuration config = new Configuration();
+        Locale loc = Locale.forLanguageTag("en");
+        LocaleList ll = new LocaleList(loc);
+        config.setLocales(ll);
+        assertEquals(loc, config.locale);
+        assertEquals(ll, config.getLocales());
+        assertEquals(View.LAYOUT_DIRECTION_LTR, config.getLayoutDirection());
+    }
+
+    public void testSetLocales_oneRtl() {
+        Configuration config = new Configuration();
+        Locale loc = Locale.forLanguageTag("az-Arab");
+        LocaleList ll = new LocaleList(loc);
+        config.setLocales(ll);
+        assertEquals(loc, config.locale);
+        assertEquals(ll, config.getLocales());
+        assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
+    }
+
+    public void testSetLocales_twoLocales() {
+        Configuration config = new Configuration();
+        Locale rtlLoc = Locale.forLanguageTag("az-Arab");
+        Locale ltrLoc = Locale.forLanguageTag("en");
+        LocaleList ll = LocaleList.forLanguageTags("az-Arab,en");
+        config.setLocales(ll);
+        assertEquals(rtlLoc, config.locale);
+        assertEquals(ll, config.getLocales());
+        assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
+    }
+
+    public void testSetLocales_overridesLocale() {
+        Configuration config = new Configuration();
+        config.locale = Locale.forLanguageTag("en");
+        LocaleList ll = LocaleList.forLanguageTags("az-Arab,en");
+        config.setLocales(ll);
+
+        assertEquals(Locale.forLanguageTag("az-Arab"), config.locale);
+        assertEquals(ll, config.getLocales());
+        assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
+    }
+
+    public void testSetLocales_overridesSetLocale() {
+        Configuration config = new Configuration();
+        config.setLocale(Locale.forLanguageTag("en"));
+        LocaleList ll = LocaleList.forLanguageTags("az-Arab,en");
+        config.setLocales(ll);
+
+        assertEquals(Locale.forLanguageTag("az-Arab"), config.locale);
+        assertEquals(ll, config.getLocales());
+        assertEquals(View.LAYOUT_DIRECTION_RTL, config.getLayoutDirection());
+    }
+
+    public void testSetLocale_overridesSetLocales() {
+        Configuration config = new Configuration();
+        config.setLocales(LocaleList.forLanguageTags("az-Arab,en"));
+        config.setLocale(Locale.ENGLISH);
+
+        assertEquals(Locale.ENGLISH, config.locale);
+        assertEquals(new LocaleList(Locale.ENGLISH), config.getLocales());
+        assertEquals(View.LAYOUT_DIRECTION_LTR, config.getLayoutDirection());
+    }
+
+    private Configuration createConfig(LocaleList list) {
+        Configuration config = createConfig();
+        config.setLocales(list);
+        return config;
     }
 
     private Configuration createConfig(Locale locale) {
+        Configuration config = createConfig();
+        config.locale = locale;
+        return config;
+    }
+
+    private Configuration createConfig() {
         Configuration config = new Configuration();
         config.fontScale = 13.37f;
         config.mcc = 0;
         config.mnc = 1;
-        config.locale = locale;
         config.touchscreen = Configuration.TOUCHSCREEN_STYLUS;
         config.keyboard = Configuration.KEYBOARD_UNDEFINED;
         config.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES;
diff --git a/tests/tests/content/src/android/content/res/cts/FractionTest.java b/tests/tests/content/src/android/content/res/cts/FractionTest.java
index 2c3e797..6a65915 100644
--- a/tests/tests/content/src/android/content/res/cts/FractionTest.java
+++ b/tests/tests/content/src/android/content/res/cts/FractionTest.java
@@ -20,7 +20,7 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.TypedValue;
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 public class FractionTest extends AndroidTestCase {
 
diff --git a/tests/tests/content/src/android/content/res/cts/PluralResourcesTest.java b/tests/tests/content/src/android/content/res/cts/PluralResourcesTest.java
index 1fd204d..7c42c9e 100644
--- a/tests/tests/content/src/android/content/res/cts/PluralResourcesTest.java
+++ b/tests/tests/content/src/android/content/res/cts/PluralResourcesTest.java
@@ -25,7 +25,7 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 public class PluralResourcesTest extends AndroidTestCase {
     public static boolean DEBUG = false;
@@ -42,7 +42,7 @@
     private Resources resourcesForLanguage(final String lang) {
         final Configuration config = new Configuration();
         config.updateFrom(mResources.getConfiguration());
-        config.locale = new Locale(lang);
+        config.setLocale(new Locale(lang));
         return new Resources(mResources.getAssets(), mResources.getDisplayMetrics(), config);
     }
 
diff --git a/tests/tests/content/src/android/content/res/cts/PrimitiveTest.java b/tests/tests/content/src/android/content/res/cts/PrimitiveTest.java
index 8eeb086..a612a15 100644
--- a/tests/tests/content/src/android/content/res/cts/PrimitiveTest.java
+++ b/tests/tests/content/src/android/content/res/cts/PrimitiveTest.java
@@ -21,7 +21,7 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.TypedValue;
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 public class PrimitiveTest extends AndroidTestCase {
     private Resources mResources;
diff --git a/tests/tests/content/src/android/content/res/cts/RawResourceTest.java b/tests/tests/content/src/android/content/res/cts/RawResourceTest.java
index c92efc7..3ca0055 100644
--- a/tests/tests/content/src/android/content/res/cts/RawResourceTest.java
+++ b/tests/tests/content/src/android/content/res/cts/RawResourceTest.java
@@ -19,7 +19,7 @@
 import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/tests/tests/content/src/android/content/res/cts/ResourceNameTest.java b/tests/tests/content/src/android/content/res/cts/ResourceNameTest.java
index a7cc03b..dde2422 100644
--- a/tests/tests/content/src/android/content/res/cts/ResourceNameTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ResourceNameTest.java
@@ -20,7 +20,7 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 public class ResourceNameTest extends AndroidTestCase {
 
@@ -29,10 +29,10 @@
         final Resources res = mContext.getResources();
 
         final String fullName = res.getResourceName(R.configVarying.simple);
-        assertEquals("com.android.cts.content:configVarying/simple", fullName);
+        assertEquals("android.content.cts:configVarying/simple", fullName);
 
         final String packageName = res.getResourcePackageName(R.configVarying.simple);
-        assertEquals("com.android.cts.content", packageName);
+        assertEquals("android.content.cts", packageName);
 
         final String typeName = res.getResourceTypeName(R.configVarying.simple);
         assertEquals("configVarying", typeName);
@@ -45,16 +45,16 @@
     public void testGetResourceIdentifier() {
         final Resources res = mContext.getResources();
         int resid = res.getIdentifier(
-                "com.android.cts.content:configVarying/simple",
+                "android.content.cts:configVarying/simple",
                 null, null);
         assertEquals(R.configVarying.simple, resid);
 
         resid = res.getIdentifier("configVarying/simple", null,
-                "com.android.cts.content");
+                "android.content.cts");
         assertEquals(R.configVarying.simple, resid);
 
         resid = res.getIdentifier("simple", "configVarying",
-                "com.android.cts.content");
+                "android.content.cts");
         assertEquals(R.configVarying.simple, resid);
     }
 }
diff --git a/tests/tests/content/src/android/content/res/cts/ResourcesTest.java b/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
index 4e2d60a..a3c1b49 100644
--- a/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
@@ -16,7 +16,7 @@
 
 package android.content.res.cts;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -35,6 +35,7 @@
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.LocaleList;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.Display;
@@ -48,9 +49,9 @@
     private static final String CONFIG_VARYING = "configVarying";
     private static final String SIMPLE = "simple";
     private static final String CONFIG_VARYING_SIMPLE = "configVarying/simple";
-    private static final String PACKAGE_NAME = "com.android.cts.content";
+    private static final String PACKAGE_NAME = "android.content.cts";
     private static final String COM_ANDROID_CTS_STUB_IDENTIFIER =
-                "com.android.cts.content:configVarying/simple";
+                "android.content.cts:configVarying/simple";
     private Resources mResources;
 
     @Override
@@ -216,14 +217,120 @@
         assertEquals(0xff00ff00, color);
     }
 
+    public Resources createNewResources() {
+        final DisplayMetrics dm = new DisplayMetrics();
+        dm.setToDefaults();
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+        return new Resources(new AssetManager(), dm, cfg);
+    }
+
     public void testUpdateConfiguration() {
-        final Configuration cfg = mResources.getConfiguration();
+        Resources res = createNewResources();
+        final Configuration cfg = new Configuration(res.getConfiguration());
         assertTrue(cfg.fontScale != 5);
 
         cfg.fontScale = 5;
-        mResources.updateConfiguration(cfg, null);
-        Configuration cfgNew = mResources.getConfiguration();
-        assertEquals(5.0f, cfgNew.fontScale, 0.001f);
+        res.updateConfiguration(cfg, null);
+        assertEquals(5.0f, res.getConfiguration().fontScale, 0.001f);
+    }
+
+    public void testUpdateConfiguration_emptyLocaleIsOverridden() {
+        Resources res = createNewResources();
+        res.getConfiguration().setLocales(null);
+        assertTrue(res.getConfiguration().getLocales().isEmpty());
+
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+        assertTrue(cfg.getLocales().isEmpty());
+
+        res.updateConfiguration(cfg, null);
+        assertEquals(LocaleList.getDefault(), res.getConfiguration().getLocales());
+    }
+
+    public void testUpdateConfiguration_copyLocales() {
+        Resources res = createNewResources();
+        final Configuration cfg = new Configuration(res.getConfiguration());
+
+        cfg.setLocales(LocaleList.forLanguageTags("az-Arab,ru"));
+
+        res.updateConfiguration(cfg, null);
+        assertEquals(LocaleList.forLanguageTags("az-Arab,ru"), res.getConfiguration().getLocales());
+    }
+
+    public void testUpdateConfiguration_emptyAfterUpdate() {
+        Resources res = createNewResources();
+        final Configuration cfg = new Configuration(res.getConfiguration());
+        cfg.setLocales(LocaleList.forLanguageTags("az-Arab"));
+
+        res.updateConfiguration(cfg, null);
+        assertEquals(LocaleList.forLanguageTags("az-Arab"), res.getConfiguration().getLocales());
+
+        res.getConfiguration().setLocales(null);
+        cfg.setLocales(null);
+        res.updateConfiguration(cfg, null);
+        assertEquals(LocaleList.getDefault(), res.getConfiguration().getLocales());
+    }
+
+    public void testUpdateConfiguration_ResolvedLocaleIsRecalculated() {
+        final DisplayMetrics dm = new DisplayMetrics();
+        dm.setToDefaults();
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+
+        // Avestan has no assets, but Czech does
+        cfg.setLocales(LocaleList.forLanguageTags("ae"));
+        Resources res = new Resources(mResources.getAssets(), dm, cfg);
+        cfg.setLocales(LocaleList.forLanguageTags("ae,cs"));
+        res.updateConfiguration(cfg, null);
+        assertEquals("cs", res.getResolvedLocale().toLanguageTag());
+    }
+
+    public void testGetResolvedLocale_unsupportedLocale() {
+        final DisplayMetrics dm = new DisplayMetrics();
+        dm.setToDefaults();
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+        cfg.setLocales(LocaleList.forLanguageTags("ae"));  // Avestan has no assets
+
+        Resources res = new Resources(mResources.getAssets(), dm, cfg);
+        assertEquals("ae", res.getResolvedLocale().toLanguageTag());
+    }
+
+    public void testGetResolvedLocale_secondaryLocaleIsSupported() {
+        final DisplayMetrics dm = new DisplayMetrics();
+        dm.setToDefaults();
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+        // Avestan has no assets, but Czech does
+        cfg.setLocales(LocaleList.forLanguageTags("ae,cs"));
+
+        Resources res = new Resources(mResources.getAssets(), dm, cfg);
+        assertEquals("cs", res.getResolvedLocale().toLanguageTag());
+    }
+
+    public void testGetResolvedLocale_secondaryLocaleIsPartiallySupported() {
+        final DisplayMetrics dm = new DisplayMetrics();
+        dm.setToDefaults();
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+        // Avestan has no assets;
+        // Persian has assets for Iran, but not Afghanistan (partial match is accepted);
+        // Czech has assets (but we don't get to it)
+        cfg.setLocales(LocaleList.forLanguageTags("ae,fa-AF,cs"));
+
+        Resources res = new Resources(mResources.getAssets(), dm, cfg);
+        assertEquals("fa-AF", res.getResolvedLocale().toLanguageTag());
+    }
+
+    public void testGetResolvedLocale_SystemResourcesLocaleNonNull() {
+        Resources res = Resources.getSystem();
+        assertNotNull(res.getResolvedLocale());
+    }
+
+    public void testGetResolvedLocale_NonNull() {
+        Resources res = createNewResources();
+        assertNotNull(res.getResolvedLocale());
     }
 
     public void testGetDimensionPixelSize() {
@@ -319,7 +426,7 @@
             //expected
         }
 
-        mResources.getValue("com.android.cts.content:raw/text", tv, false);
+        mResources.getValue("android.content.cts:raw/text", tv, false);
         assertNotNull(tv);
         assertEquals("res/raw/text.txt", tv.coerceToString());
     }
@@ -456,7 +563,7 @@
     private Resources resourcesForLanguage(final String lang) {
         final Configuration config = new Configuration();
         config.updateFrom(mResources.getConfiguration());
-        config.locale = new Locale(lang);
+        config.setLocale(new Locale(lang));
         return new Resources(mResources.getAssets(), mResources.getDisplayMetrics(), config);
     }
 
diff --git a/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java b/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java
index 6d1c2e4..e31ffd6 100644
--- a/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java
+++ b/tests/tests/content/src/android/content/res/cts/Resources_ThemeTest.java
@@ -29,7 +29,7 @@
 import android.util.Xml;
 import android.view.View;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 import java.util.Locale;
 
diff --git a/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java b/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
index 346bb9b..2eb82a8 100644
--- a/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
+++ b/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
@@ -16,7 +16,7 @@
 
 package android.content.res.cts;
 
-import com.android.cts.content.R;
+import android.content.cts.R;
 
 import org.xmlpull.v1.XmlPullParserException;
 
diff --git a/tests/tests/database/Android.mk b/tests/tests/database/Android.mk
index 8557c60..a554528 100644
--- a/tests/tests/database/Android.mk
+++ b/tests/tests/database/Android.mk
@@ -29,4 +29,7 @@
 
 LOCAL_PACKAGE_NAME := CtsDatabaseTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/database/AndroidManifest.xml b/tests/tests/database/AndroidManifest.xml
index fefcc1f..f9043db 100644
--- a/tests/tests/database/AndroidManifest.xml
+++ b/tests/tests/database/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.database">
+    package="android.database.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -24,7 +24,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.database"
+                     android:targetPackage="android.database.cts"
                      android:label="CTS tests of android.database">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/database/AndroidTest.xml b/tests/tests/database/AndroidTest.xml
new file mode 100644
index 0000000..046215d
--- /dev/null
+++ b/tests/tests/database/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Database test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsDatabaseTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.database.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/display/Android.mk b/tests/tests/display/Android.mk
index f17f580..dc815c3 100644
--- a/tests/tests/display/Android.mk
+++ b/tests/tests/display/Android.mk
@@ -16,17 +16,26 @@
 
 include $(CLEAR_VARS)
 
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-# and when built explicitly put it in the data partition
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_PACKAGE_NAME := CtsDisplayTestCases
 
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/display/AndroidManifest.xml b/tests/tests/display/AndroidManifest.xml
index bf84219..22cc824 100644
--- a/tests/tests/display/AndroidManifest.xml
+++ b/tests/tests/display/AndroidManifest.xml
@@ -16,9 +16,8 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.display">
+    package="android.display.cts">
 
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <!-- For special presentation windows when testing mode switches. -->
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
 
@@ -26,12 +25,11 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.display"
-                     android:label="CTS tests of android.view.display">
-        <meta-data
-            android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
+    <!--  self-instrumenting test package. -->
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.display.cts"
+        android:label="CTS tests of android.display">
     </instrumentation>
 
 </manifest>
diff --git a/tests/tests/display/AndroidTest.xml b/tests/tests/display/AndroidTest.xml
index dd42984..f346c22 100644
--- a/tests/tests/display/AndroidTest.xml
+++ b/tests/tests/display/AndroidTest.xml
@@ -13,9 +13,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Base config for CTS package preparer">
-    <include name="common-config" />
-    <!-- Use a non-standard pattern, must match values in tests/tests/display/.../DisplayTest.java -->
-    <option name="run-command:run-command" value="settings put global overlay_display_devices '181x161/214|181x161/214'" />
-    <option name="run-command:teardown-command" value="settings put global overlay_display_devices &quot;&quot;" />
-</configuration>
+<configuration description="Config for CTS Acceleration test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsDisplayTestCases.apk" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <!-- Use a non-standard pattern, must match values in tests/tests/display/.../DisplayTest.java -->
+        <option name="run-command" value="settings put global overlay_display_devices '181x161/214|181x161/214'" />
+        <option name="teardown-command" value="settings put global overlay_display_devices &quot;&quot;" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.display.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/display/OldAndroidTest.xml b/tests/tests/display/OldAndroidTest.xml
new file mode 100644
index 0000000..dd42984
--- /dev/null
+++ b/tests/tests/display/OldAndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Base config for CTS package preparer">
+    <include name="common-config" />
+    <!-- Use a non-standard pattern, must match values in tests/tests/display/.../DisplayTest.java -->
+    <option name="run-command:run-command" value="settings put global overlay_display_devices '181x161/214|181x161/214'" />
+    <option name="run-command:teardown-command" value="settings put global overlay_display_devices &quot;&quot;" />
+</configuration>
diff --git a/tests/tests/dpi/Android.mk b/tests/tests/dpi/Android.mk
index 4c05ecf..c961c4c 100644
--- a/tests/tests/dpi/Android.mk
+++ b/tests/tests/dpi/Android.mk
@@ -30,6 +30,9 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
 
 # ============================================================
diff --git a/tests/tests/dpi/AndroidManifest.xml b/tests/tests/dpi/AndroidManifest.xml
index 0197056..118050e 100644
--- a/tests/tests/dpi/AndroidManifest.xml
+++ b/tests/tests/dpi/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.dpi">
+    package="android.dpi.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -27,7 +27,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.dpi"
+                     android:targetPackage="android.dpi.cts"
                      android:label="CTS tests for DPI">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/dpi/AndroidTest.xml b/tests/tests/dpi/AndroidTest.xml
new file mode 100644
index 0000000..b8d941b
--- /dev/null
+++ b/tests/tests/dpi/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS DPI test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsDpiTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.dpi.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/dpi/src/android/dpi/cts/DefaultManifestAttributesSdkTest.java b/tests/tests/dpi/src/android/dpi/cts/DefaultManifestAttributesSdkTest.java
index 9253eca..d11f3ae 100644
--- a/tests/tests/dpi/src/android/dpi/cts/DefaultManifestAttributesSdkTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/DefaultManifestAttributesSdkTest.java
@@ -24,7 +24,7 @@
  */
 public class DefaultManifestAttributesSdkTest extends DefaultManifestAttributesTest {
     protected String getPackageName() {
-        return "com.android.cts.dpi";
+        return "android.dpi.cts";
     }
 
     // This is a sanity test to make sure that we're instrumenting the proper package
diff --git a/tests/tests/dpi2/Android.mk b/tests/tests/dpi2/Android.mk
index 03a687d..af1207d 100644
--- a/tests/tests/dpi2/Android.mk
+++ b/tests/tests/dpi2/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/dpi2/AndroidManifest.xml b/tests/tests/dpi2/AndroidManifest.xml
index 6dbdc23..bb21910 100644
--- a/tests/tests/dpi2/AndroidManifest.xml
+++ b/tests/tests/dpi2/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.dpi2">
+    package="android.dpi2.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -28,7 +28,7 @@
     <uses-sdk android:targetSdkVersion="3" />
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.dpi2"
+                     android:targetPackage="android.dpi2.cts"
                      android:label="CTS tests for DPI">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/dpi2/AndroidTest.xml b/tests/tests/dpi2/AndroidTest.xml
new file mode 100644
index 0000000..dfb1730
--- /dev/null
+++ b/tests/tests/dpi2/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS DPI test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsDpiTestCases2.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.dpi2.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/dpi2/src/android/dpi2/cts/DefaultManifestAttributesCupcakeTest.java b/tests/tests/dpi2/src/android/dpi2/cts/DefaultManifestAttributesCupcakeTest.java
index 27a082b..04db412 100644
--- a/tests/tests/dpi2/src/android/dpi2/cts/DefaultManifestAttributesCupcakeTest.java
+++ b/tests/tests/dpi2/src/android/dpi2/cts/DefaultManifestAttributesCupcakeTest.java
@@ -29,7 +29,7 @@
  */
 public class DefaultManifestAttributesCupcakeTest extends DefaultManifestAttributesTest {
     protected String getPackageName() {
-        return "com.android.cts.dpi2";
+        return "android.dpi2.cts";
     }
 
     // This is a sanity test to make sure that we're instrumenting the proper package
diff --git a/tests/tests/dreams/Android.mk b/tests/tests/dreams/Android.mk
index 87bd357..8a4c499 100644
--- a/tests/tests/dreams/Android.mk
+++ b/tests/tests/dreams/Android.mk
@@ -33,4 +33,7 @@
 # Need access to ServiceManager - see b/13307221
 #LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/dreams/AndroidManifest.xml b/tests/tests/dreams/AndroidManifest.xml
index b395a4f..8f1d75e 100644
--- a/tests/tests/dreams/AndroidManifest.xml
+++ b/tests/tests/dreams/AndroidManifest.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.dreams">
+    package="android.dreams.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -23,7 +23,7 @@
 
     <!-- This is a self-instrumenting test package. -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.dreams"
+                     android:targetPackage="android.dreams.cts"
                      android:label="CTS tests for the android.service.dreams package">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/dreams/AndroidTest.xml b/tests/tests/dreams/AndroidTest.xml
new file mode 100644
index 0000000..b334ade
--- /dev/null
+++ b/tests/tests/dreams/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Dreams test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsDreamsTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.dreams.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/drm/Android.mk b/tests/tests/drm/Android.mk
index 6272e9c..db6ec92 100644
--- a/tests/tests/drm/Android.mk
+++ b/tests/tests/drm/Android.mk
@@ -28,6 +28,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_PACKAGE_NAME := CtsDrmTestCases
 
 LOCAL_JNI_SHARED_LIBRARIES := \
diff --git a/tests/tests/drm/AndroidManifest.xml b/tests/tests/drm/AndroidManifest.xml
index 527d498..c4ea03d 100644
--- a/tests/tests/drm/AndroidManifest.xml
+++ b/tests/tests/drm/AndroidManifest.xml
@@ -14,8 +14,7 @@
      limitations under the License.
 -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.drm">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.drm.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -23,11 +22,10 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.drm"
+                     android:targetPackage="android.drm.cts"
                      android:label="CTS tests of android.drm">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
 
 </manifest>
-
diff --git a/tests/tests/drm/AndroidTest.xml b/tests/tests/drm/AndroidTest.xml
new file mode 100644
index 0000000..48287aa
--- /dev/null
+++ b/tests/tests/drm/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS DRM test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsDrmTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.drm.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/effect/Android.mk b/tests/tests/effect/Android.mk
index 6a9778e..aac0d73 100644
--- a/tests/tests/effect/Android.mk
+++ b/tests/tests/effect/Android.mk
@@ -28,6 +28,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/effect/AndroidManifest.xml b/tests/tests/effect/AndroidManifest.xml
index 481be14..81f3bbf 100644
--- a/tests/tests/effect/AndroidManifest.xml
+++ b/tests/tests/effect/AndroidManifest.xml
@@ -14,8 +14,7 @@
      limitations under the License.
 -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.effect">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.effect.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -24,7 +23,7 @@
 
     <!-- This is a self-instrumenting test package. -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.effect"
+                     android:targetPackage="android.effect.cts"
                      android:label="CTS tests of android.media.effect component">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/effect/AndroidTest.xml b/tests/tests/effect/AndroidTest.xml
new file mode 100644
index 0000000..abf2b22
--- /dev/null
+++ b/tests/tests/effect/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Effect test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsEffectTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.effect.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/gesture/Android.mk b/tests/tests/gesture/Android.mk
index 4a97931..0c4e023 100755
--- a/tests/tests/gesture/Android.mk
+++ b/tests/tests/gesture/Android.mk
@@ -16,15 +16,22 @@
 
 include $(CLEAR_VARS)
 
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-# and when built explicitly put it in the data partition
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_PACKAGE_NAME := CtsGestureTestCases
 
 LOCAL_SDK_VERSION := current
diff --git a/tests/tests/gesture/AndroidManifest.xml b/tests/tests/gesture/AndroidManifest.xml
index b288cd2..fb3ee51 100755
--- a/tests/tests/gesture/AndroidManifest.xml
+++ b/tests/tests/gesture/AndroidManifest.xml
@@ -16,19 +16,17 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.gesture">
+    package="android.gesture.cts">
 
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
 
     <!--  self-instrumenting test package. -->
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.gesture"
-                     android:label="CTS tests of android.gesture">
-        <meta-data android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.gesture.cts"
+        android:label="CTS tests of android.gesture">
     </instrumentation>
 
 </manifest>
diff --git a/tests/tests/gesture/AndroidTest.xml b/tests/tests/gesture/AndroidTest.xml
new file mode 100644
index 0000000..497cad1
--- /dev/null
+++ b/tests/tests/gesture/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Gesture test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsGestureTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.gesture.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/graphics/Android.mk b/tests/tests/graphics/Android.mk
index 773b47d..feb9f4d 100644
--- a/tests/tests/graphics/Android.mk
+++ b/tests/tests/graphics/Android.mk
@@ -24,6 +24,9 @@
 
 LOCAL_PACKAGE_NAME := CtsGraphicsTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/graphics/AndroidManifest.xml b/tests/tests/graphics/AndroidManifest.xml
index 4249bb3..f14506f 100644
--- a/tests/tests/graphics/AndroidManifest.xml
+++ b/tests/tests/graphics/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.graphics">
+    package="android.graphics.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -54,7 +54,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.graphics"
+                     android:targetPackage="android.graphics.cts"
                      android:label="CTS tests of android.graphics">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/graphics/AndroidTest.xml b/tests/tests/graphics/AndroidTest.xml
new file mode 100644
index 0000000..a9f746b
--- /dev/null
+++ b/tests/tests/graphics/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Graphics test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsGraphicsTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.graphics.cts" />
+        <option name="runtime-hint" value="5m" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/vector_icon_fill_state_list.xml b/tests/tests/graphics/res/color/vector_icon_fill_state_list.xml
new file mode 100644
index 0000000..f5b4632
--- /dev/null
+++ b/tests/tests/graphics/res/color/vector_icon_fill_state_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2015 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.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#00ff00" android:state_pressed="true" />
+    <item android:color="#0000ff" />
+</selector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/color/vector_icon_stroke_state_list.xml b/tests/tests/graphics/res/color/vector_icon_stroke_state_list.xml
new file mode 100644
index 0000000..bbc635e
--- /dev/null
+++ b/tests/tests/graphics/res/color/vector_icon_stroke_state_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2015 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.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#0000ff" android:state_pressed="true" />
+    <item android:color="#00ff00" />
+</selector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_arcto_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_arcto_golden.png
new file mode 100644
index 0000000..7ba0f17
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_arcto_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_implicit_lineto_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_implicit_lineto_golden.png
new file mode 100644
index 0000000..9d74952
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_implicit_lineto_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
index c60dfba..d24321c 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
index e7cc4d1..7e35798 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
index c7c049b..1427f4b 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png
new file mode 100644
index 0000000..3936c89
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden_pressed.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden_pressed.png
new file mode 100644
index 0000000..c5d06f6
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden_pressed.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/custom_drawable.xml b/tests/tests/graphics/res/drawable/custom_drawable.xml
new file mode 100644
index 0000000..cfb9bdb
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/custom_drawable.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<drawable xmlns:android="http://schemas.android.com/apk/res/android"
+    class="android.graphics.drawable.cts.CustomDrawableTest$CustomDrawable"
+    android:color="#ffff0000" />
diff --git a/tests/tests/graphics/res/drawable/gradient_drawable_density.xml b/tests/tests/graphics/res/drawable/gradient_drawable_density.xml
new file mode 100644
index 0000000..ad3a3be
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/gradient_drawable_density.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="ring"
+    android:innerRadius="10dp"
+    android:thickness="4dp">
+    <gradient
+        android:gradientRadius="10dp" />
+    <corners
+        android:topLeftRadius="8dp"
+        android:topRightRadius="9dp"
+        android:bottomLeftRadius="10dp"
+        android:bottomRightRadius="11dp" />
+    <padding
+        android:left="11dp"
+        android:top="12dp"
+        android:right="13dp"
+        android:bottom="14dp" />
+    <stroke
+        android:color="@android:color/black"
+        android:dashGap="4dp"
+        android:dashWidth="4dp"
+        android:width="2dp" />
+    <size
+        android:width="200dp"
+        android:height="200dp" />
+</shape>
diff --git a/tests/tests/graphics/res/drawable/grayscale_jpg.jpg b/tests/tests/graphics/res/drawable/grayscale_jpg.jpg
new file mode 100644
index 0000000..6c6ae32
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/grayscale_jpg.jpg
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/grayscale_png.png b/tests/tests/graphics/res/drawable/grayscale_png.png
new file mode 100644
index 0000000..9f1beac
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/grayscale_png.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/inset_color.xml b/tests/tests/graphics/res/drawable/inset_color.xml
new file mode 100644
index 0000000..55cdf22
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/inset_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:drawable="@android:color/white"
+       android:inset="10dp" />
+
diff --git a/tests/tests/graphics/res/drawable/inset_density.xml b/tests/tests/graphics/res/drawable/inset_density.xml
new file mode 100644
index 0000000..7e0823e
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/inset_density.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:drawable="@drawable/inset_testimage"
+       android:insetLeft="16dp" />
diff --git a/tests/tests/graphics/res/drawable/inset_mutate.xml b/tests/tests/graphics/res/drawable/inset_mutate.xml
index ba613e9..feeeda1 100644
--- a/tests/tests/graphics/res/drawable/inset_mutate.xml
+++ b/tests/tests/graphics/res/drawable/inset_mutate.xml
@@ -16,4 +16,4 @@
  -->
 
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:drawable="@drawable/inset_mutate_testimage" />
+       android:drawable="@drawable/inset_testimage" />
diff --git a/tests/tests/graphics/res/drawable/inset_mutate_testimage.jpg b/tests/tests/graphics/res/drawable/inset_testimage.jpg
similarity index 100%
rename from tests/tests/graphics/res/drawable/inset_mutate_testimage.jpg
rename to tests/tests/graphics/res/drawable/inset_testimage.jpg
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/layer_drawable_density.xml b/tests/tests/graphics/res/drawable/layer_drawable_density.xml
new file mode 100644
index 0000000..3012539
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/layer_drawable_density.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:paddingLeft="8dp"
+    android:paddingRight="8dp"
+    android:paddingMode="nest">
+    <item
+        android:left="16dp"
+        android:right="16dp"
+        android:top="16dp"
+        android:bottom="16dp"
+        android:width="32dp"
+        android:height="32dp">
+        <color
+            android:color="@android:color/black" />
+    </item>
+</layer-list>
diff --git a/tests/tests/graphics/res/drawable/layer_drawable_intrinsic.xml b/tests/tests/graphics/res/drawable/layer_drawable_intrinsic.xml
new file mode 100644
index 0000000..0a8cd98
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/layer_drawable_intrinsic.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:left="5dp"
+          android:right="5dp"
+          android:top="5dp"
+          android:bottom="5dp"
+          android:drawable="@android:color/black" />
+</layer-list>
diff --git a/tests/tests/graphics/res/drawable/layer_drawable_intrinsic_mixed.xml b/tests/tests/graphics/res/drawable/layer_drawable_intrinsic_mixed.xml
new file mode 100644
index 0000000..a590f90
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/layer_drawable_intrinsic_mixed.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:left="2dp"
+          android:right="2dp"
+          android:top="2dp"
+          android:bottom="2dp"
+          android:drawable="@drawable/size_48x48" />
+    <item android:left="100dp"
+          android:right="100dp"
+          android:top="100dp"
+          android:bottom="100dp"
+          android:drawable="@android:color/black" />
+</layer-list>
diff --git a/tests/tests/graphics/res/drawable/state_list_density.xml b/tests/tests/graphics/res/drawable/state_list_density.xml
new file mode 100644
index 0000000..9a17384
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/state_list_density.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+   <item android:state_focused="true" android:drawable="@drawable/state_list_density_1" />
+   <item android:drawable="@drawable/state_list_density_2" />
+</selector>
+
diff --git a/tests/tests/graphics/res/drawable/inset_mutate_testimage.jpg b/tests/tests/graphics/res/drawable/state_list_density_1.jpg
similarity index 100%
copy from tests/tests/graphics/res/drawable/inset_mutate_testimage.jpg
copy to tests/tests/graphics/res/drawable/state_list_density_1.jpg
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/state_list_density_2.jpg b/tests/tests/graphics/res/drawable/state_list_density_2.jpg
new file mode 100644
index 0000000..f963c86
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/state_list_density_2.jpg
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/state_list_density_constant_size.xml b/tests/tests/graphics/res/drawable/state_list_density_constant_size.xml
new file mode 100644
index 0000000..4e183f3
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/state_list_density_constant_size.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:constantSize="true">
+   <item android:state_focused="true" android:drawable="@drawable/state_list_density_1" />
+   <item android:drawable="@drawable/state_list_density_2" />
+</selector>
+
diff --git a/tests/tests/graphics/res/drawable/vector_density.xml b/tests/tests/graphics/res/drawable/vector_density.xml
new file mode 100644
index 0000000..c3ca1981
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_density.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2015 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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="24"
+        android:viewportWidth="24" >
+
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_arcto.xml b/tests/tests/graphics/res/drawable/vector_icon_arcto.xml
new file mode 100644
index 0000000..6038d2b
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_arcto.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="20dp"
+        android:height="50dp"
+        android:viewportWidth="20.0"
+        android:viewportHeight="50.0">
+    <path
+        android:pathData="M14.285706,47.362198A50.71429,62.14286 0,0 0,1.0630035 5.5146027"
+        android:fillColor="#ff55ff"/>
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_implicit_lineto.xml b/tests/tests/graphics/res/drawable/vector_icon_implicit_lineto.xml
new file mode 100644
index 0000000..d7b133b
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_implicit_lineto.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2015 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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="64"
+        android:viewportWidth="64" >
+
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="m0,0 32,0 0,32 -32,0 0,-32z" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/vector_icon_state_list.xml b/tests/tests/graphics/res/drawable/vector_icon_state_list.xml
new file mode 100644
index 0000000..65aa967
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_state_list.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2015 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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="24"
+        android:viewportWidth="24" >
+
+    <path
+        android:fillColor="@color/vector_icon_fill_state_list"
+        android:strokeColor="@color/vector_icon_stroke_state_list"
+        android:strokeWidth="3"
+        android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z"/>
+
+</vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/xml/scaledrawable_level.xml b/tests/tests/graphics/res/xml/scaledrawable_level.xml
new file mode 100644
index 0000000..6a7ec74
--- /dev/null
+++ b/tests/tests/graphics/res/xml/scaledrawable_level.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 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.
+ -->
+
+<alias xmlns:android="http://schemas.android.com/apk/res/android">
+    <scale_allattrs>
+        <scale xmlns:android="http://schemas.android.com/apk/res/android"
+            android:fromXScale="1.0"
+            android:toXScale="1.4"
+            android:fromYScale="1.0"
+            android:toYScale="0.6"
+            android:drawable="@drawable/testimage"
+            android:level="5000" />
+    </scale_allattrs>
+</alias>
\ No newline at end of file
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index 2314ffb..a93fd27 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 
 import android.content.res.Resources;
@@ -64,12 +64,10 @@
     private static int HEIGHTS[] = new int[] { 960, 480, 240, 240, 480 };
 
     // Configurations for BitmapFactory.Options
-    private static Config[] COLOR_CONFIGS = new Config[] {Config.ARGB_8888, Config.RGB_565,
-        Config.ARGB_4444};
+    private static Config[] COLOR_CONFIGS = new Config[] {Config.ARGB_8888, Config.RGB_565};
     private static int[] COLOR_TOLS = new int[] {16, 49, 576};
 
-    private static Config[] COLOR_CONFIGS_RGBA = new Config[] {Config.ARGB_8888,
-        Config.ARGB_4444};
+    private static Config[] COLOR_CONFIGS_RGBA = new Config[] {Config.ARGB_8888};
     private static int[] COLOR_TOLS_RGBA = new int[] {72, 124};
 
     private static int[] RAW_COLORS = new int[] {
@@ -573,6 +571,116 @@
         verifyScaled(BitmapFactory.decodeStream(obtainInputStream(), null, scaledOpt));
     }
 
+    public void testConfigs() {
+        // The output Config of a BitmapFactory decode depends on the request from the
+        // client and the properties of the image to be decoded.
+        //
+        // Options.inPreferredConfig = Config.ARGB_8888
+        //     This is the default value of inPreferredConfig.  In this case, the image
+        //     will always be decoded to Config.ARGB_8888.
+        // Options.inPreferredConfig = Config.RGB_565
+        //     If the encoded image is opaque, we will decode to Config.RGB_565,
+        //     otherwise we will decode to whichever color type is the most natural match
+        //     for the encoded data.
+        // Options.inPreferredConfig = Config.ARGB_4444
+        //     This is deprecated and will always decode to Config.ARGB_8888.
+        // Options.inPreferredConfig = Config.ALPHA_8
+        //     If the encoded image is gray, we will decode to 8-bit grayscale values
+        //     and indicate that the output bitmap is Config.ALPHA_8.  This is somewhat
+        //     misleading because the image is really opaque and grayscale, but we are
+        //     labeling each pixel as if it is a translucency (alpha) value.  If the
+        //     encoded image is not gray, we will decode to whichever color type is the
+        //     most natural match for the encoded data.
+        // Options.inPreferredConfig = null
+        //     We will decode to whichever Config is the most natural match with the
+        //     encoded data.  This could be 8-bit indices into a color table (call this
+        //     INDEX_8), ALPHA_8 (gray), or ARGB_8888.
+        //
+        // This test ensures that images are decoded to the intended Config and that the
+        // decodes match regardless of the Config.
+        decodeConfigs(R.drawable.alpha, 31, 31, true, false, false);
+        decodeConfigs(R.drawable.baseline_jpeg, 1280, 960, false, false, false);
+        decodeConfigs(R.drawable.bmp_test, 320, 240, false, false, false);
+        decodeConfigs(R.drawable.scaled2, 6, 8, false, false, true);
+        decodeConfigs(R.drawable.grayscale_jpg, 128, 128, false, true, false);
+        decodeConfigs(R.drawable.grayscale_png, 128, 128, false, true, false);
+    }
+
+    private void decodeConfigs(int id, int width, int height, boolean hasAlpha, boolean isGray,
+            boolean hasColorTable) {
+        Options opts = new BitmapFactory.Options();
+        opts.inScaled = false;
+        assertEquals(Config.ARGB_8888, opts.inPreferredConfig);
+        Bitmap reference = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(reference);
+        assertEquals(width, reference.getWidth());
+        assertEquals(height, reference.getHeight());
+        assertEquals(Config.ARGB_8888, reference.getConfig());
+
+        opts.inPreferredConfig = Config.ARGB_4444;
+        Bitmap argb4444 = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(argb4444);
+        assertEquals(width, argb4444.getWidth());
+        assertEquals(height, argb4444.getHeight());
+        // ARGB_4444 is deprecated and we should decode to ARGB_8888.
+        assertEquals(Config.ARGB_8888, argb4444.getConfig());
+        compareBitmaps(reference, argb4444, 0, true, true);
+
+        opts.inPreferredConfig = Config.RGB_565;
+        Bitmap rgb565 = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(rgb565);
+        assertEquals(width, rgb565.getWidth());
+        assertEquals(height, rgb565.getHeight());
+        if (!hasAlpha) {
+            assertEquals(Config.RGB_565, rgb565.getConfig());
+            // Convert the RGB_565 bitmap to ARGB_8888 and test that it is similar to
+            // the reference.  We lose information when decoding to 565, so there must
+            // be some tolerance.  The tolerance is intentionally loose to allow us some
+            // flexibility regarding if we dither and how we color convert.
+            compareBitmaps(reference, rgb565.copy(Config.ARGB_8888, false), 30, true, true);
+        }
+
+        opts.inPreferredConfig = Config.ALPHA_8;
+        Bitmap alpha8 = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(alpha8);
+        assertEquals(width, reference.getWidth());
+        assertEquals(height, reference.getHeight());
+        if (isGray) {
+            assertEquals(Config.ALPHA_8, alpha8.getConfig());
+            // Convert the ALPHA_8 bitmap to ARGB_8888 and test that it is identical to
+            // the reference.  We must do this manually because we are abusing ALPHA_8
+            // in order to represent grayscale.
+            compareBitmaps(reference, grayToARGB(alpha8), 0, true, true);
+        }
+
+        // Setting inPreferredConfig to null selects the most natural color type for
+        // the encoded data.  If the image has a color table, this should be INDEX_8.
+        // If we decode to INDEX_8, the output bitmap will report that the Config is
+        // null.
+        opts.inPreferredConfig = null;
+        Bitmap index8 = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(index8);
+        assertEquals(width, index8.getWidth());
+        assertEquals(height, index8.getHeight());
+        if (hasColorTable) {
+            assertEquals(null, index8.getConfig());
+            // Convert the INDEX_8 bitmap to ARGB_8888 and test that it is identical to
+            // the reference.
+            compareBitmaps(reference, index8.copy(Config.ARGB_8888, false), 0, true, true);
+        }
+    }
+
+    private Bitmap grayToARGB(Bitmap gray) {
+        Bitmap argb = Bitmap.createBitmap(gray.getWidth(), gray.getHeight(), Config.ARGB_8888);
+        for (int y = 0; y < argb.getHeight(); y++) {
+            for (int x = 0; x < argb.getWidth(); x++) {
+                int grayByte = Color.alpha(gray.getPixel(x, y));
+                argb.setPixel(x, y, Color.rgb(grayByte, grayByte, grayByte));
+            }
+        }
+        return argb;
+    }
+
     private byte[] obtainArray() {
         ByteArrayOutputStream stm = new ByteArrayOutputStream();
         Options opt = new BitmapFactory.Options();
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
index adce1c4..328d9ed 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
@@ -29,7 +29,7 @@
 import android.test.InstrumentationTestCase;
 import android.util.Log;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 
 import java.io.ByteArrayOutputStream;
@@ -304,6 +304,83 @@
         }
     }
 
+    // The documentation for BitmapRegionDecoder guarantees that, when reusing a
+    // bitmap, "the provided Bitmap's width, height, and Bitmap.Config will not
+    // be changed".  If the inBitmap is too small, decoded content will be
+    // clipped into inBitmap.  Here we test that:
+    //     (1) If inBitmap is specified, it is always used.
+    //     (2) The width, height, and Config of inBitmap are never changed.
+    //     (3) All of the pixels decoded into inBitmap exactly match the pixels
+    //         of a decode where inBitmap is NULL.
+    public void testInBitmapReuse() throws IOException {
+        Options defaultOpts = new BitmapFactory.Options();
+        Options reuseOpts = new BitmapFactory.Options();
+        Rect subset = new Rect(0, 0, TILE_SIZE, TILE_SIZE);
+
+        for (int i = 0; i < NUM_TEST_IMAGES; i++) {
+            InputStream is = obtainInputStream(RES_IDS[i]);
+            BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
+            for (int j = 0; j < SAMPLESIZES.length; j++) {
+                int sampleSize = SAMPLESIZES[j];
+                defaultOpts.inSampleSize = sampleSize;
+                reuseOpts.inSampleSize = sampleSize;
+
+                // We don't need to worry about rounding here because sampleSize
+                // divides evenly into TILE_SIZE.
+                assertEquals(0, TILE_SIZE % sampleSize);
+                int scaledDim = TILE_SIZE / sampleSize;
+                int chunkSize = scaledDim / 2;
+                for (int k = 0; k < COLOR_CONFIGS.length; k++) {
+                    Config config = COLOR_CONFIGS[k];
+                    defaultOpts.inPreferredConfig = config;
+                    reuseOpts.inPreferredConfig = config;
+
+                    // For both the width and the height of inBitmap, we test three
+                    // interesting cases:
+                    // (1) inBitmap dimension is smaller than scaledDim.  The decoded
+                    //     pixels that fit inside inBitmap should exactly match the
+                    //     corresponding decoded pixels from the same region decode,
+                    //     performed without an inBitmap.  The pixels that do not fit
+                    //     inside inBitmap should be clipped.
+                    // (2) inBitmap dimension matches scaledDim.  After the decode,
+                    //     the pixels and dimensions of inBitmap should exactly match
+                    //     those of the result bitmap of the same region decode,
+                    //     performed without an inBitmap.
+                    // (3) inBitmap dimension is larger than scaledDim.  After the
+                    //     decode, inBitmap should contain decoded pixels for the
+                    //     entire region, exactly matching the decoded pixels
+                    //     produced when inBitmap is not specified.  The additional
+                    //     pixels in inBitmap are left the same as before the decode.
+                    for (int w = chunkSize; w <= 3 * chunkSize; w += chunkSize) {
+                        for (int h = chunkSize; h <= 3 * chunkSize; h += chunkSize) {
+                            // Decode reusing inBitmap.
+                            reuseOpts.inBitmap = Bitmap.createBitmap(w, h, config);
+                            Bitmap reuseResult = decoder.decodeRegion(subset, reuseOpts);
+                            assertSame(reuseOpts.inBitmap, reuseResult);
+                            assertEquals(reuseResult.getWidth(), w);
+                            assertEquals(reuseResult.getHeight(), h);
+                            assertEquals(reuseResult.getConfig(), config);
+
+                            // Decode into a new bitmap.
+                            Bitmap defaultResult = decoder.decodeRegion(subset, defaultOpts);
+                            assertEquals(defaultResult.getWidth(), scaledDim);
+                            assertEquals(defaultResult.getHeight(), scaledDim);
+
+                            // Ensure that the decoded pixels of reuseResult and defaultResult
+                            // are identical.
+                            int cropWidth = Math.min(w, scaledDim);
+                            int cropHeight = Math.min(h, scaledDim);
+                            Rect crop = new Rect(0 ,0, cropWidth, cropHeight);
+                            Bitmap reuseCropped = cropBitmap(reuseResult, crop);
+                            Bitmap defaultCropped = cropBitmap(defaultResult, crop);
+                            compareBitmaps(reuseCropped, defaultCropped, 0, true);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     private void compareRegionByRegion(BitmapRegionDecoder decoder,
             Options opts, int mseMargin, Bitmap wholeImage) {
         int width = decoder.getWidth();
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
index 07e65d2..f820771 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
@@ -15,7 +15,7 @@
  */
 package android.graphics.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 
 import android.content.res.Resources;
diff --git a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
index 1dd6777..dee217b 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
@@ -41,7 +41,7 @@
 import android.text.SpannableStringBuilder;
 import android.text.SpannedString;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import java.util.Vector;
 
@@ -348,6 +348,117 @@
         verifySaveFlagsSequence(flags);
     }
 
+    // This test exercises the saveLayer flag that preserves the clip
+    // state across the matching restore call boundary. This is a vanilla
+    // test and doesn't exercise any interaction between the clip stack
+    // and SkCanvas' deferred save/restore system.
+    public void testSaveFlags9() {
+        Rect clip0 = new Rect();
+        assertTrue(mCanvas.getClipBounds(clip0));
+
+        mCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+
+            // All clip elements should be preserved after restore
+            mCanvas.clipRect(0, 0, BITMAP_WIDTH / 2, BITMAP_HEIGHT);
+            Path path = new Path();
+            path.addOval(0.25f * BITMAP_WIDTH, 0.25f * BITMAP_HEIGHT,
+                         0.75f * BITMAP_WIDTH, 0.75f * BITMAP_HEIGHT,
+                         Path.Direction.CW);
+            mCanvas.clipPath(path);
+            mCanvas.clipRect(0, 0, BITMAP_WIDTH, BITMAP_HEIGHT / 2);
+
+            Rect clip1 = new Rect();
+            assertTrue(mCanvas.getClipBounds(clip1));
+            assertTrue(clip1 != clip0);
+            assertTrue(clip0.contains(clip1));
+
+        mCanvas.restore();
+
+        Rect clip2 = new Rect();
+        assertTrue(mCanvas.getClipBounds(clip2));
+        assertEquals(clip2, clip1);
+    }
+
+    // This test exercises the saveLayer MATRIX_SAVE_FLAG flag and its
+    // interaction with the clip stack and SkCanvas deferred save/restore
+    // system.
+    public void testSaveFlags10() {
+        RectF rect1 = new RectF(0, 0, BITMAP_WIDTH / 2, BITMAP_HEIGHT);
+        RectF rect2 = new RectF(0, 0, BITMAP_WIDTH, BITMAP_HEIGHT / 2);
+        Path path = new Path();
+        path.addOval(0.25f * BITMAP_WIDTH, 0.25f * BITMAP_HEIGHT,
+                     0.75f * BITMAP_WIDTH, 0.75f * BITMAP_HEIGHT,
+                     Path.Direction.CW);
+
+        Rect clip0 = new Rect();
+        assertTrue(mCanvas.getClipBounds(clip0));
+
+        // Exercise various Canvas lazy-save interactions.
+        mCanvas.save();
+            mCanvas.save();
+                mCanvas.clipRect(rect1);
+                mCanvas.clipPath(path);
+
+                Rect clip1 = new Rect();
+                assertTrue(mCanvas.getClipBounds(clip1));
+                assertTrue(clip1 != clip0);
+
+                mCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+                    mCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+                        mCanvas.clipRect(rect2);
+                        mCanvas.clipPath(path);
+
+                        Rect clip2 = new Rect();
+                        assertTrue(mCanvas.getClipBounds(clip2));
+                        assertTrue(clip2 != clip1);
+                        assertTrue(clip2 != clip0);
+
+                        mCanvas.save();
+                            mCanvas.translate(10, 5);
+                            mCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+                                // An uncommitted save/restore frame: exercises
+                                // the partial save emulation, ensuring there
+                                // are no side effects.
+                                Rect clip3 = new Rect();
+                                assertTrue(mCanvas.getClipBounds(clip3));
+                                clip3.offset(10, 5); // adjust for local offset
+                                assertEquals(clip3, clip2);
+                            mCanvas.restore();
+
+                            Rect clip4 = new Rect();
+                            assertTrue(mCanvas.getClipBounds(clip4));
+                            clip4.offset(10, 5); // adjust for local offset
+                            assertEquals(clip4, clip2);
+                        mCanvas.restore();
+
+                        Rect clip5 = new Rect();
+                        assertTrue(mCanvas.getClipBounds(clip5));
+                        assertEquals(clip5, clip2);
+                    mCanvas.restore();
+
+                    // clip2 survives the preceding restore
+                    Rect clip6 = new Rect();
+                    assertTrue(mCanvas.getClipBounds(clip6));
+                    assertEquals(clip6, clip2);
+                mCanvas.restore();
+
+                // clip2 also survives the preceding restore
+                Rect clip7 = new Rect();
+                assertTrue(mCanvas.getClipBounds(clip7));
+                assertEquals(clip7, clip2);
+            mCanvas.restore();
+
+            // clip1 does _not_ survive the preceding restore
+            Rect clip8 = new Rect();
+            assertTrue(mCanvas.getClipBounds(clip8));
+            assertEquals(clip8, clip0);
+        mCanvas.restore();
+
+        Rect clip9 = new Rect();
+        assertTrue(mCanvas.getClipBounds(clip9));
+        assertEquals(clip9, clip0);
+    }
+
     public void testSaveLayer1() {
         final Paint p = new Paint();
         final RectF rF = new RectF(0, 10, 31, 0);
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageViewCtsActivity.java b/tests/tests/graphics/src/android/graphics/cts/ImageViewCtsActivity.java
index b9887b7..9d6de44 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageViewCtsActivity.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.graphics.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/graphics/src/android/graphics/cts/MovieTest.java b/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
index b18b800..c1e7ead 100644
--- a/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
@@ -32,10 +32,10 @@
 
 public class MovieTest extends ActivityInstrumentationTestCase2<MockActivity> {
     private Movie mMovie;
-    private final int MOVIE = com.android.cts.graphics.R.drawable.animated;
+    private final int MOVIE = android.graphics.cts.R.drawable.animated;
 
     public MovieTest() {
-        super("com.android.cts.graphics", MockActivity.class);
+        super("android.graphics.cts", MockActivity.class);
     }
 
     @Override
diff --git a/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java b/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
index d37ec90..8b73380 100644
--- a/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 
 import android.content.res.Resources;
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index 80e0253..c813bdb 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -36,6 +36,7 @@
 import android.os.Build;
 import android.test.AndroidTestCase;
 import android.text.SpannedString;
+import android.util.LocaleList;
 import android.util.Log;
 
 import java.util.Locale;
@@ -600,30 +601,73 @@
         // Check default
         assertEquals(defaultLocale, p.getTextLocale());
 
-        // Check setter / getter
+        // Check setter / getters
         p.setTextLocale(Locale.US);
         assertEquals(Locale.US, p.getTextLocale());
+        assertEquals(new LocaleList(Locale.US), p.getTextLocales());
 
         p.setTextLocale(Locale.CHINESE);
         assertEquals(Locale.CHINESE, p.getTextLocale());
+        assertEquals(new LocaleList(Locale.CHINESE), p.getTextLocales());
 
         p.setTextLocale(Locale.JAPANESE);
         assertEquals(Locale.JAPANESE, p.getTextLocale());
+        assertEquals(new LocaleList(Locale.JAPANESE), p.getTextLocales());
 
         p.setTextLocale(Locale.KOREAN);
         assertEquals(Locale.KOREAN, p.getTextLocale());
+        assertEquals(new LocaleList(Locale.KOREAN), p.getTextLocales());
 
         // Check reverting back to default
         p.setTextLocale(defaultLocale);
         assertEquals(defaultLocale, p.getTextLocale());
+        assertEquals(new LocaleList(defaultLocale), p.getTextLocales());
 
         // Check that we cannot pass a null locale
         try {
             p.setTextLocale(null);
-            assertFalse(true);
+            fail("Setting the text locale to null should throw");
+        } catch (Throwable e) {
+            assertEquals(IllegalArgumentException.class, e.getClass());
         }
-        catch (IllegalArgumentException iae) {
-            // OK !!
+    }
+
+    public void testAccessTextLocales() {
+        Paint p = new Paint();
+
+        final LocaleList defaultLocales = LocaleList.getDefault();
+
+        // Check default
+        assertEquals(defaultLocales, p.getTextLocales());
+
+        // Check setter / getters for a one-member locale list
+        p.setTextLocales(new LocaleList(Locale.CHINESE));
+        assertEquals(Locale.CHINESE, p.getTextLocale());
+        assertEquals(new LocaleList(Locale.CHINESE), p.getTextLocales());
+
+        // Check setter / getters for a two-member locale list
+        p.setTextLocales(LocaleList.forLanguageTags("fr,de"));
+        assertEquals(Locale.forLanguageTag("fr"), p.getTextLocale());
+        assertEquals(LocaleList.forLanguageTags("fr,de"), p.getTextLocales());
+
+        // Check reverting back to default
+        p.setTextLocales(defaultLocales);
+        assertEquals(defaultLocales, p.getTextLocales());
+
+        // Check that we cannot pass a null locale list
+        try {
+            p.setTextLocales(null);
+            fail("Setting the text locale list to null should throw");
+        } catch (Throwable e) {
+            assertEquals(IllegalArgumentException.class, e.getClass());
+        }
+
+        // Check that we cannot pass an empty locale list
+        try {
+            p.setTextLocales(new LocaleList());
+            fail("Setting the text locale list to an empty list should throw");
+        } catch (Throwable e) {
+            assertEquals(IllegalArgumentException.class, e.getClass());
         }
     }
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/YuvImageTest.java b/tests/tests/graphics/src/android/graphics/cts/YuvImageTest.java
index 02b3afa..a2038b4 100644
--- a/tests/tests/graphics/src/android/graphics/cts/YuvImageTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/YuvImageTest.java
@@ -33,7 +33,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 
 public class YuvImageTest extends AndroidTestCase {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
index 769e110..2368d08 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
@@ -28,7 +28,7 @@
 import android.util.Log;
 import android.util.Xml;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java
index 28a3c6b..60da3ad 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -50,7 +50,7 @@
     private Resources mResources;
 
     public AnimationDrawableTest() {
-        super("com.android.cts.graphics", ImageViewCtsActivity.class);
+        super("android.graphics.cts", ImageViewCtsActivity.class);
     }
 
     @Override
@@ -275,6 +275,23 @@
         pollingCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
         // do not repeat
         assertStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                // Set visible to false and restart to false
+                mAnimationDrawable.setVisible(false, false);
+            }
+        });
+        // Check that animation drawable stays on the same frame
+        assertStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                // Set visible to true and restart to false
+                mAnimationDrawable.setVisible(true, false);
+            }
+        });
+        // Check that animation drawable stays on the same frame
+        assertStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
     }
 
     public void testInflateCorrect() throws XmlPullParserException, IOException {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
index 88e7acb..9b11cf7 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -316,29 +316,48 @@
 
         InputStream source = mContext.getResources().openRawResource(R.drawable.size_48x48);
         bitmapDrawable = new BitmapDrawable(source);
-        bitmapDrawable.setTargetDensity(mContext.getResources().getDisplayMetrics().densityDpi);
+        bitmapDrawable.setTargetDensity(bitmapDrawable.getBitmap().getDensity());
         assertEquals(48, bitmapDrawable.getIntrinsicWidth());
         assertEquals(48, bitmapDrawable.getIntrinsicHeight());
     }
 
     @SuppressWarnings("deprecation")
     public void testSetTargetDensity() {
-        BitmapDrawable bitmapDrawable = new BitmapDrawable();
+        int sourceWidth, targetWidth;
+        int sourceHeight, targetHeight;
+        int sourceDensity, targetDensity;
+        BitmapDrawable bitmapDrawable;
+        Bitmap bitmap;
 
-        Bitmap bitmap = Bitmap.createBitmap(200, 300, Config.RGB_565);
+        sourceWidth = 200;
+        sourceHeight = 300;
+        bitmap = Bitmap.createBitmap(sourceWidth, sourceHeight, Config.RGB_565);
         Canvas canvas = new Canvas(bitmap);
         bitmapDrawable = new BitmapDrawable(bitmap);
-        bitmapDrawable.setTargetDensity(canvas.getDensity());
-        assertEquals(200, bitmapDrawable.getIntrinsicWidth());
-        assertEquals(300, bitmapDrawable.getIntrinsicHeight());
+        sourceDensity = bitmap.getDensity();
+        targetDensity = canvas.getDensity();
+        bitmapDrawable.setTargetDensity(targetDensity);
+        targetWidth = DrawableTestUtils.scaleBitmapFromDensity(
+                sourceWidth, sourceDensity, targetDensity);
+        targetHeight = DrawableTestUtils.scaleBitmapFromDensity(
+                sourceHeight, sourceDensity, targetDensity);
+        assertEquals(targetWidth, bitmapDrawable.getIntrinsicWidth());
+        assertEquals(targetHeight, bitmapDrawable.getIntrinsicHeight());
 
-        DisplayMetrics disMetrics = new DisplayMetrics();
-        disMetrics = getInstrumentation().getTargetContext().getResources().getDisplayMetrics();
+        sourceWidth = 48;
+        sourceHeight = 48;
         InputStream source = mContext.getResources().openRawResource(R.drawable.size_48x48);
         bitmapDrawable = new BitmapDrawable(source);
-        bitmapDrawable.setTargetDensity(disMetrics.densityDpi);
-        assertEquals(48, bitmapDrawable.getIntrinsicWidth());
-        assertEquals(48, bitmapDrawable.getIntrinsicHeight());
+        bitmap = bitmapDrawable.getBitmap();
+        sourceDensity = bitmap.getDensity();
+        targetDensity = sourceDensity * 2;
+        bitmapDrawable.setTargetDensity(targetDensity);
+        targetWidth = DrawableTestUtils.scaleBitmapFromDensity(
+                sourceWidth, sourceDensity, targetDensity);
+        targetHeight = DrawableTestUtils.scaleBitmapFromDensity(
+                sourceHeight, sourceDensity, targetDensity);
+        assertEquals(targetWidth, bitmapDrawable.getIntrinsicWidth());
+        assertEquals(targetHeight, bitmapDrawable.getIntrinsicHeight());
     }
 
     @SuppressWarnings("deprecation")
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java
index e727350..074cbd9 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ColorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ColorDrawableTest.java
index 465a476..c092f3c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ColorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ColorDrawableTest.java
@@ -26,7 +26,7 @@
 import android.util.AttributeSet;
 import android.util.Xml;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/CustomDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/CustomDrawableTest.java
new file mode 100644
index 0000000..7dff729
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/CustomDrawableTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 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.graphics.drawable.cts;
+
+import android.graphics.cts.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.test.AndroidTestCase;
+import android.util.AttributeSet;
+
+import java.io.IOException;
+
+public class CustomDrawableTest extends AndroidTestCase {
+
+    public void testInflation() {
+        Drawable dr = getContext().getDrawable(R.drawable.custom_drawable);
+        assertTrue(dr instanceof CustomDrawable);
+        assertEquals(Color.RED, ((CustomDrawable) dr).getColor());
+    }
+
+    public static class CustomDrawable extends Drawable {
+        private static final int[] ATTRS = new int[] { android.R.attr.color };
+
+        private int mColor;
+
+        @Override
+        public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+                throws XmlPullParserException, IOException {
+            super.inflate(r, parser, attrs, theme);
+
+            final TypedArray ta;
+            if (theme != null) {
+                ta = theme.obtainStyledAttributes(attrs, ATTRS, 0, 0);
+            } else {
+                ta = r.obtainAttributes(attrs, ATTRS);
+            }
+
+            mColor = ta.getColor(0, Color.BLACK);
+        }
+
+        public int getColor() {
+            return mColor;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter colorFilter) {
+
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.OPAQUE;
+        }
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java
index a91353f..0858c6b 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java
@@ -17,7 +17,7 @@
 package android.graphics.drawable.cts;
 
 import android.view.View;
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
index a0fa634..ae28eca 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
@@ -16,15 +16,17 @@
 
 package android.graphics.drawable.cts;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.util.AttributeSet;
 import android.util.Xml;
 
 import java.io.IOException;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 /**
  * The useful methods for graphics.drawable test.
  */
@@ -85,4 +87,41 @@
         }
         return attrs;
     }
+
+    public static XmlResourceParser getResourceParser(Resources res, int resId)
+            throws XmlPullParserException, IOException {
+        final XmlResourceParser parser = res.getXml(resId);
+        int type;
+        while ((type = parser.next()) != XmlPullParser.START_TAG
+                && type != XmlPullParser.END_DOCUMENT) {
+            // Empty loop
+        }
+        return parser;
+    }
+
+    public static void setResourcesDensity(Resources res, int densityDpi) {
+        final Configuration config = new Configuration();
+        config.setTo(res.getConfiguration());
+        config.densityDpi = densityDpi;
+        res.updateConfiguration(config, null);
+    }
+
+    /**
+     * Implements scaling as used by the Bitmap class. Resulting values are
+     * rounded up (as distinct from resource scaling, which truncates or rounds
+     * to the nearest pixel).
+     *
+     * @param size the pixel size to scale
+     * @param sdensity the source density that corresponds to the size
+     * @param tdensity the target density
+     * @return the pixel size scaled for the target density
+     */
+    public static int scaleBitmapFromDensity(int size, int sdensity, int tdensity) {
+        if (sdensity == 0 || tdensity == 0 || sdensity == tdensity) {
+            return size;
+        }
+
+        // Scale by tdensity / sdensity, rounding up.
+        return ((size * tdensity) + (sdensity >> 1)) / sdensity;
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableWrapperTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableWrapperTest.java
index 40680c1..9037e6a 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableWrapperTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableWrapperTest.java
@@ -17,7 +17,7 @@
 package android.graphics.drawable.cts;
 
 import android.graphics.drawable.DrawableWrapper;
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 
 import java.util.Arrays;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
index eeda22c..c80ae4b 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
@@ -16,7 +16,9 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import android.content.res.Resources.Theme;
+import android.content.res.XmlResourceParser;
+import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -320,4 +322,70 @@
         assertEquals(50, d3.getIntrinsicHeight());
         assertEquals(40, d3.getIntrinsicWidth());
     }
+
+    public void testPreloadDensity() throws XmlPullParserException, IOException {
+        final Resources res = getContext().getResources();
+        final int densityDpi = res.getConfiguration().densityDpi;
+        final Rect tempPadding = new Rect();
+
+        // Capture initial state at default density.
+        final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+                res, R.drawable.gradient_drawable_density);
+        final GradientDrawable preloadedDrawable = new GradientDrawable();
+        preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
+        final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+        final int origWidth = preloadedDrawable.getIntrinsicWidth();
+        final int origHeight = preloadedDrawable.getIntrinsicHeight();
+        final Rect origPadding = new Rect();
+        preloadedDrawable.getPadding(origPadding);
+
+        // Set density to half of original. Unlike offsets, which are
+        // truncated, dimensions are rounded to the nearest pixel.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
+        final GradientDrawable halfDrawable =
+                (GradientDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
+        assertEquals(Math.round(origHeight / 2f), halfDrawable.getIntrinsicHeight());
+        assertTrue(halfDrawable.getPadding(tempPadding));
+        assertEquals((int) (origPadding.left / 2f), tempPadding.left);
+
+        // Set density to double original.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
+        final GradientDrawable doubleDrawable =
+                (GradientDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(origWidth * 2, doubleDrawable.getIntrinsicWidth());
+        assertEquals(origHeight * 2, doubleDrawable.getIntrinsicHeight());
+        assertTrue(doubleDrawable.getPadding(tempPadding));
+        assertEquals(origPadding.left * 2, tempPadding.left);
+
+        // Restore original density.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi);
+        final GradientDrawable origDrawable =
+                (GradientDrawable) preloadedConstantState.newDrawable();
+        assertEquals(origWidth, origDrawable.getIntrinsicWidth());
+        assertEquals(origHeight, origDrawable.getIntrinsicHeight());
+        assertTrue(origDrawable.getPadding(tempPadding));
+        assertEquals(origPadding, tempPadding);
+
+        // Some precision is lost when scaling the half-density
+        // drawable back up to the original density.
+        final Rect sloppyOrigPadding = new Rect();
+        sloppyOrigPadding.left = 2 * Math.round(origPadding.left / 2f);
+        sloppyOrigPadding.top = 2 * Math.round(origPadding.top / 2f);
+        sloppyOrigPadding.right = 2 * Math.round(origPadding.right / 2f);
+        sloppyOrigPadding.bottom = 2 * Math.round(origPadding.bottom / 2f);
+
+        // Ensure theme density is applied correctly.
+        final Theme t = res.newTheme();
+        halfDrawable.applyTheme(t);
+        assertEquals(2 * Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
+        assertEquals(2 * Math.round(origHeight / 2f), halfDrawable.getIntrinsicHeight());
+        assertTrue(halfDrawable.getPadding(tempPadding));
+        assertEquals(sloppyOrigPadding, tempPadding);
+        doubleDrawable.applyTheme(t);
+        assertEquals(origWidth, doubleDrawable.getIntrinsicWidth());
+        assertEquals(origHeight, doubleDrawable.getIntrinsicHeight());
+        assertTrue(doubleDrawable.getPadding(tempPadding));
+        assertEquals(origPadding, tempPadding);
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java
index d89ce7c..299eaf0 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import android.app.Activity;
 import android.app.Instrumentation;
@@ -50,7 +50,7 @@
     MockRunner mRunner;
 
     public IconTest() {
-        super("com.android.cts.graphics", ImageViewCtsActivity.class);
+        super("android.graphics.cts", ImageViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
index 9c5f063..fb10db6 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
@@ -16,23 +16,25 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.XmlResourceParser;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.cts.R;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
 import android.graphics.drawable.Drawable.ConstantState;
+import android.graphics.drawable.InsetDrawable;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.StateSet;
 import android.util.Xml;
+import android.view.InflateException;
 
 import java.io.IOException;
 import java.util.Arrays;
@@ -57,23 +59,25 @@
 
         try {
             insetDrawable.inflate(r, parser, attrs);
-            fail("There should be a XmlPullParserException thrown out.");
-        } catch (XmlPullParserException e) {
+            fail("There should be an InflateException thrown out.");
+        } catch (InflateException e) {
             // expected, test success
         } catch (IOException e) {
             fail("There should not be an IOException thrown out.");
+        } catch (XmlPullParserException e) {
+            fail("There should not be a XmlPullParserException thrown out.");
         }
 
         // input null as params
         try {
             insetDrawable.inflate(null, null, null);
             fail("There should be a NullPointerException thrown out.");
-        } catch (XmlPullParserException e) {
-            fail("There should not be a XmlPullParserException thrown out.");
-        } catch (IOException e) {
-            fail("There should not be an IOException thrown out.");
         } catch (NullPointerException e) {
             // expected, test success
+        } catch (IOException e) {
+            fail("There should not be an IOException thrown out.");
+        } catch (XmlPullParserException e) {
+            fail("There should not be a XmlPullParserException thrown out.");
         }
     }
 
@@ -283,28 +287,48 @@
         Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
-        int expected = d.getIntrinsicWidth(); /* 31 */
+        int expected = d.getIntrinsicWidth();
         assertEquals(expected, insetDrawable.getIntrinsicWidth());
 
         d = mContext.getDrawable(R.drawable.scenery);
         insetDrawable = new InsetDrawable(d, 0);
 
-        expected = d.getIntrinsicWidth(); /* 170 */
+        expected = d.getIntrinsicWidth();
         assertEquals(expected, insetDrawable.getIntrinsicWidth());
+
+        d = mContext.getDrawable(R.drawable.scenery);
+        insetDrawable = new InsetDrawable(d, 20);
+
+        expected = d.getIntrinsicWidth() + 40;
+        assertEquals(expected, insetDrawable.getIntrinsicWidth());
+
+        d = mContext.getDrawable(R.drawable.inset_color);
+        expected = -1;
+        assertEquals(expected, d.getIntrinsicWidth());
     }
 
     public void testGetIntrinsicHeight() {
         Drawable d = mContext.getDrawable(R.drawable.pass);
         InsetDrawable insetDrawable = new InsetDrawable(d, 0);
 
-        int expected = d.getIntrinsicHeight(); /* 31 */
+        int expected = d.getIntrinsicHeight();
         assertEquals(expected, insetDrawable.getIntrinsicHeight());
 
         d = mContext.getDrawable(R.drawable.scenery);
         insetDrawable = new InsetDrawable(d, 0);
 
-        expected = d.getIntrinsicHeight(); /* 107 */
+        expected = d.getIntrinsicHeight();
         assertEquals(expected, insetDrawable.getIntrinsicHeight());
+
+        d = mContext.getDrawable(R.drawable.scenery);
+        insetDrawable = new InsetDrawable(d, 20);
+
+        expected = d.getIntrinsicHeight() + 40;
+        assertEquals(expected, insetDrawable.getIntrinsicHeight());
+
+        d = mContext.getDrawable(R.drawable.inset_color);
+        expected = -1;
+        assertEquals(expected, d.getIntrinsicHeight());
     }
 
     public void testGetConstantState() {
@@ -333,6 +357,51 @@
         assertEquals("Did not modify post-mutate() instance", 255, post.getDrawable().getAlpha());
     }
 
+    public void testPreloadDensity() throws XmlPullParserException, IOException {
+        final Resources res = getContext().getResources();
+        final int densityDpi = res.getConfiguration().densityDpi;
+
+        // Capture initial state at default density.
+        final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+                res, R.drawable.inset_density);
+        final InsetDrawable preloadedDrawable = new InsetDrawable(null, 0);
+        preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
+        final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+        final int origInsetHoriz = preloadedDrawable.getIntrinsicWidth()
+                - preloadedDrawable.getDrawable().getIntrinsicWidth();
+
+        // Set density to half of original. Unlike offsets, which are
+        // truncated, dimensions are rounded to the nearest pixel.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
+        final InsetDrawable halfDrawable =
+                (InsetDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(Math.round(origInsetHoriz / 2f), halfDrawable.getIntrinsicWidth()
+                - halfDrawable.getDrawable().getIntrinsicWidth());
+
+        // Set density to double original.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
+        final InsetDrawable doubleDrawable =
+                (InsetDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(origInsetHoriz * 2, doubleDrawable.getIntrinsicWidth()
+                - doubleDrawable.getDrawable().getIntrinsicWidth());
+
+        // Restore original density.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi);
+        final InsetDrawable origDrawable =
+                (InsetDrawable) preloadedConstantState.newDrawable();
+        assertEquals(origInsetHoriz, origDrawable.getIntrinsicWidth()
+                - origDrawable.getDrawable().getIntrinsicWidth());
+
+        // Ensure theme density is applied correctly.
+        final Theme t = res.newTheme();
+        halfDrawable.applyTheme(t);
+        assertEquals(origInsetHoriz, halfDrawable.getIntrinsicWidth()
+                - halfDrawable.getDrawable().getIntrinsicWidth());
+        doubleDrawable.applyTheme(t);
+        assertEquals(origInsetHoriz, doubleDrawable.getIntrinsicWidth()
+                - doubleDrawable.getDrawable().getIntrinsicWidth());
+    }
+
     private class MockInsetDrawable extends InsetDrawable {
         public MockInsetDrawable(Drawable drawable, int inset) {
             super(drawable, inset);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
index a2f9ddf..4b17587 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
@@ -16,19 +16,18 @@
 
 package android.graphics.drawable.cts;
 
-import android.view.Gravity;
-import com.android.cts.graphics.R;
-
+import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.IOException;
-
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.cts.R;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -41,8 +40,12 @@
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.StateSet;
+import android.util.Xml;
+import android.view.Gravity;
 import android.view.View;
 
+import java.io.IOException;
+
 public class LayerDrawableTest extends AndroidTestCase {
 
     @SuppressWarnings("deprecation")
@@ -258,7 +261,12 @@
 
     @SuppressWarnings("deprecation")
     public void testSetLayerInset() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+        MockDrawable firstLayer = new MockDrawable();
+        firstLayer.setIntrinsicSize(10, 10);
+        MockDrawable secondLayer = new MockDrawable();
+        secondLayer.setIntrinsicSize(-1, -1);
+
+        Drawable[] array = new Drawable[] { firstLayer, secondLayer };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -272,15 +280,12 @@
         assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
                 layerDrawable.getIntrinsicHeight());
 
-        // set bigger inset for layer 1
-        left += 10;
-        top += 10;
-        right += 10;
-        bottom += 10;
-        layerDrawable.setLayerInset(1, left, top, right, bottom);
-        assertEquals(layerDrawable.getDrawable(1).getIntrinsicWidth() + left + right,
+        // The drawable at index 0 has no intrinsic width or height, so it
+        // won't be counted for the overall intrinsic width or height.
+        layerDrawable.setLayerInset(1, 10, 10, 10, 10);
+        assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
                 layerDrawable.getIntrinsicWidth());
-        assertEquals(layerDrawable.getDrawable(1).getIntrinsicHeight() + top + bottom,
+        assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
                 layerDrawable.getIntrinsicHeight());
 
         try {
@@ -640,6 +645,21 @@
         assertTrue(mockDrawable2.hasCalledOnBoundsChange());
     }
 
+    public void testJumpToCurrentState() {
+        MockDrawable mockDrawable1 = new MockDrawable();
+        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
+        LayerDrawable layerDrawable = new LayerDrawable(array);
+
+        assertFalse(mockDrawable1.hasCalledJumpToCurrentState());
+        assertFalse(mockDrawable2.hasCalledJumpToCurrentState());
+
+        layerDrawable.jumpToCurrentState();
+
+        assertTrue(mockDrawable1.hasCalledJumpToCurrentState());
+        assertTrue(mockDrawable2.hasCalledJumpToCurrentState());
+    }
+
     public void testSetLevel() {
         MockDrawable mockDrawable1 = new MockDrawable();
         MockDrawable mockDrawable2 = new MockDrawable();
@@ -720,11 +740,13 @@
     }
 
     public void testGetIntrinsicWidth() {
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
-        Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
+        MockDrawable largeMockDrawable = new MockDrawable();
+        largeMockDrawable.setIntrinsicSize(10, 10);
+        MockDrawable smallMockDrawable = new MockDrawable();
+        smallMockDrawable.setIntrinsicSize(1, 1);
+        Drawable[] array = new Drawable[] { largeMockDrawable, smallMockDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
-        assertEquals(mockDrawable1.getIntrinsicWidth(), layerDrawable.getIntrinsicWidth());
+        assertEquals(largeMockDrawable.getIntrinsicWidth(), layerDrawable.getIntrinsicWidth());
 
         Rect inset1 = new Rect(1, 2, 3, 4);
         Rect inset2 = new Rect(2, 4, 6, 7);
@@ -732,26 +754,28 @@
         Rect padding2 = new Rect(21, 32, 43, 54);
         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
         layerDrawable.setLayerInset(1, inset2.left, inset2.top, inset2.right, inset2.bottom);
-        mockDrawable1.setPadding(padding1);
-        mockDrawable2.setPadding(padding2);
+        largeMockDrawable.setPadding(padding1);
+        smallMockDrawable.setPadding(padding2);
         layerDrawable.getPadding(new Rect());
-        assertEquals(mockDrawable2.getIntrinsicWidth() + inset2.left
+        assertEquals(smallMockDrawable.getIntrinsicWidth() + inset2.left
                 + inset2.right + padding1.left + padding1.right,
                 layerDrawable.getIntrinsicWidth());
 
         inset1 = new Rect(inset2.left + padding1.left + 1, inset2.top + padding1.top + 1,
                 inset2.right + padding1.right + 1, inset2.bottom + padding1.bottom + 1);
         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
-        assertEquals(mockDrawable1.getIntrinsicWidth() + inset1.left + inset1.right,
+        assertEquals(largeMockDrawable.getIntrinsicWidth() + inset1.left + inset1.right,
                 layerDrawable.getIntrinsicWidth());
     }
 
     public void testGetIntrinsicHeight() {
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
-        Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
+        MockDrawable largeMockDrawable = new MockDrawable();
+        largeMockDrawable.setIntrinsicSize(10, 10);
+        MockDrawable smallMockDrawable = new MockDrawable();
+        smallMockDrawable.setIntrinsicSize(1, 1);
+        Drawable[] array = new Drawable[] { largeMockDrawable, smallMockDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
-        assertEquals(mockDrawable1.getIntrinsicHeight(), layerDrawable.getIntrinsicHeight());
+        assertEquals(largeMockDrawable.getIntrinsicHeight(), layerDrawable.getIntrinsicHeight());
 
         Rect inset1 = new Rect(1, 2, 3, 4);
         Rect inset2 = new Rect(2, 4, 6, 7);
@@ -759,17 +783,17 @@
         Rect padding2 = new Rect(21, 32, 43, 54);
         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
         layerDrawable.setLayerInset(1, inset2.left, inset2.top, inset2.right, inset2.bottom);
-        mockDrawable1.setPadding(padding1);
-        mockDrawable2.setPadding(padding2);
+        largeMockDrawable.setPadding(padding1);
+        smallMockDrawable.setPadding(padding2);
         layerDrawable.getPadding(new Rect());
-        assertEquals(mockDrawable2.getIntrinsicHeight() + inset2.top
+        assertEquals(smallMockDrawable.getIntrinsicHeight() + inset2.top
                 + inset2.bottom + padding1.top + padding1.bottom,
                 layerDrawable.getIntrinsicHeight());
 
         inset1 = new Rect(inset2.left + padding1.left + 1, inset2.top + padding1.top + 1,
                 inset2.right + padding1.right + 1, inset2.bottom + padding1.bottom + 1);
         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
-        assertEquals(mockDrawable1.getIntrinsicHeight() + inset1.top + inset1.bottom,
+        assertEquals(largeMockDrawable.getIntrinsicHeight() + inset1.top + inset1.bottom,
                 layerDrawable.getIntrinsicHeight());
     }
 
@@ -1056,10 +1080,14 @@
 
     @SuppressWarnings("deprecation")
     public void testSetLayerInsetRelative() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+        MockDrawable firstLayer = new MockDrawable();
+        firstLayer.setIntrinsicSize(10, 10);
+        MockDrawable secondLayer = new MockDrawable();
+        secondLayer.setIntrinsicSize(-1, -1);
+
+        Drawable[] array = new Drawable[] { firstLayer, secondLayer };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
-        // set inset for layer 0
         int start = 10;
         int top = 20;
         int end = 30;
@@ -1069,25 +1097,21 @@
                 layerDrawable.getIntrinsicWidth());
         assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
                 layerDrawable.getIntrinsicHeight());
-        assertEquals(10, layerDrawable.getLayerInsetStart(0));
-        assertEquals(20, layerDrawable.getLayerInsetTop(0));
-        assertEquals(30, layerDrawable.getLayerInsetEnd(0));
-        assertEquals(40, layerDrawable.getLayerInsetBottom(0));
+        assertEquals(start, layerDrawable.getLayerInsetStart(0));
+        assertEquals(top, layerDrawable.getLayerInsetTop(0));
+        assertEquals(end, layerDrawable.getLayerInsetEnd(0));
+        assertEquals(bottom, layerDrawable.getLayerInsetBottom(0));
         assertEquals(0, layerDrawable.getLayerInsetLeft(0));
         assertEquals(0, layerDrawable.getLayerInsetRight(0));
 
-        // set bigger inset for layer 1
-        start += 10;
-        top += 10;
-        end += 10;
-        bottom += 10;
-        layerDrawable.setLayerInsetRelative(1, start, top, end, bottom);
-        assertEquals(layerDrawable.getDrawable(1).getIntrinsicWidth() + start + end,
+        // The drawable at index 1 has no intrinsic width or height, so it
+        // won't be counted for the overall intrinsic width or height.
+        layerDrawable.setLayerInsetRelative(1, 10, 10, 10, 10);
+        assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
                 layerDrawable.getIntrinsicWidth());
-        assertEquals(layerDrawable.getDrawable(1).getIntrinsicHeight() + top + bottom,
+        assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
                 layerDrawable.getIntrinsicHeight());
 
-
         try {
             layerDrawable.setLayerInsetRelative(-1, start, top, end, bottom);
             fail("Should throw IndexOutOfBoundsException");
@@ -1390,7 +1414,29 @@
         }
     }
 
+    public void testChildIntrinsicSize() {
+        LayerDrawable dr;
 
+        // Ensure that a child with no intrinsic size correctly reports bounds.
+        dr = (LayerDrawable) getContext().getDrawable(R.drawable.layer_drawable_intrinsic);
+        assertEquals(-1, dr.getIntrinsicWidth());
+        assertEquals(-1, dr.getIntrinsicHeight());
+
+        // Check when creating the drawble from code.
+        dr = new LayerDrawable(new Drawable[] { new ColorDrawable(Color.RED) });
+        dr.setLayerInset(0, 10, 10, 10, 10);
+        assertEquals(-1, dr.getIntrinsicWidth());
+        assertEquals(-1, dr.getIntrinsicHeight());
+
+        // Ensure mixed children report bounds correctly as well.
+        dr = (LayerDrawable) getContext().getDrawable(R.drawable.layer_drawable_intrinsic_mixed);
+        int width = dr.getLayerInsetLeft(0) + dr.getLayerInsetRight(0)
+                + dr.getDrawable(0).getIntrinsicWidth();
+        int height = dr.getLayerInsetTop(0) + dr.getLayerInsetBottom(0)
+                + dr.getDrawable(0).getIntrinsicHeight();
+        assertEquals(width, dr.getIntrinsicWidth());
+        assertEquals(height, dr.getIntrinsicHeight());
+    }
 
     private static class MockDrawable extends Drawable {
         private boolean mCalledSetDither = false;
@@ -1400,7 +1446,7 @@
         private boolean mCalledSetState = false;
         private boolean mCalledOnLevelChange = false;
         private boolean mCalledOnBoundsChange = false;
-
+        private boolean mCalledJumpToCurrentState = false;
 
         private boolean mCalledDraw = false;
 
@@ -1408,6 +1454,9 @@
 
         private int mOpacity = PixelFormat.OPAQUE;
 
+        private int mIntrinsicWidth = -1;
+        private int mIntrinsicHeight = -1;
+
         private boolean mDither = false;
 
         Rect mPadding = null;
@@ -1454,6 +1503,21 @@
             mCalledSetDither = true;
         }
 
+        public void setIntrinsicSize(int width, int height) {
+            mIntrinsicWidth = width;
+            mIntrinsicHeight = height;
+        }
+
+        @Override
+        public int getIntrinsicWidth() {
+            return mIntrinsicWidth;
+        }
+
+        @Override
+        public int getIntrinsicHeight() {
+            return mIntrinsicHeight;
+        }
+
         public boolean hasCalledSetDither() {
             return mCalledSetDither;
         }
@@ -1474,11 +1538,23 @@
             mCalledSetState = false;
             mCalledOnLevelChange = false;
             mCalledOnBoundsChange = false;
+            mCalledJumpToCurrentState = false;
 
             mCalledDraw = false;
         }
 
         @Override
+        public void jumpToCurrentState() {
+            super.jumpToCurrentState();
+
+            mCalledJumpToCurrentState = true;
+        }
+
+        public boolean hasCalledJumpToCurrentState() {
+            return mCalledJumpToCurrentState;
+        }
+
+        @Override
         protected boolean onStateChange(int[] state) {
             increasePadding();
             return mIsStateful;
@@ -1583,4 +1659,103 @@
         assertEquals(50, ((BitmapDrawable) d3.getDrawable(0)).getPaint().getAlpha());
         assertEquals(50, ((BitmapDrawable) d3.getDrawable(0)).getPaint().getAlpha());
     }
+
+    public void testPreloadDensity() throws XmlPullParserException, IOException {
+        final Resources res = getContext().getResources();
+        final int densityDpi = res.getConfiguration().densityDpi;
+
+        // Capture initial state at default density.
+        final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+                res, R.drawable.layer_drawable_density);
+        final LayerDrawable preloadedDrawable = new LayerDrawable(new Drawable[0]);
+        preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
+        final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+        final int initialWidth = preloadedDrawable.getIntrinsicWidth();
+        final int initialLeftPadding = preloadedDrawable.getLeftPadding();
+        final int initialRightPadding = preloadedDrawable.getRightPadding();
+        final int initialBottomPadding = preloadedDrawable.getBottomPadding();
+        final int initialTopPadding = preloadedDrawable.getTopPadding();
+        final int initialLayerInsetLeft = preloadedDrawable.getLayerInsetLeft(0);
+        final int initialLayerInsetRight = preloadedDrawable.getLayerInsetRight(0);
+        final int initialLayerInsetTop = preloadedDrawable.getLayerInsetTop(0);
+        final int initialLayerInsetBottom = preloadedDrawable.getLayerInsetBottom(0);
+        final int initialLayerWidth = preloadedDrawable.getLayerWidth(0);
+        final int initialLayerHeight = preloadedDrawable.getLayerHeight(0);
+
+        // Set density to half of original. Unlike offsets, which are
+        // truncated, dimensions are rounded to the nearest pixel.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
+        final LayerDrawable halfDrawable =
+                (LayerDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(Math.round(initialWidth / 2f), halfDrawable.getIntrinsicWidth());
+        assertEquals(Math.round(initialLeftPadding / 2f), halfDrawable.getLeftPadding());
+        assertEquals(Math.round(initialRightPadding / 2f), halfDrawable.getRightPadding());
+        assertEquals(Math.round(initialBottomPadding / 2f), halfDrawable.getBottomPadding());
+        assertEquals(Math.round(initialTopPadding / 2f), halfDrawable.getTopPadding());
+        assertEquals(Math.round(initialLayerInsetLeft / 2f),halfDrawable.getLayerInsetLeft(0));
+        assertEquals(Math.round(initialLayerInsetRight / 2f), halfDrawable.getLayerInsetRight(0));
+        assertEquals(Math.round(initialLayerInsetTop / 2f), halfDrawable.getLayerInsetTop(0));
+        assertEquals(Math.round(initialLayerInsetBottom / 2f), halfDrawable.getLayerInsetBottom(0));
+        assertEquals(Math.round(initialLayerWidth / 2f), halfDrawable.getLayerWidth(0));
+        assertEquals(Math.round(initialLayerHeight / 2f), halfDrawable.getLayerHeight(0));
+
+        // Set density to double original.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
+        final LayerDrawable doubleDrawable =
+                (LayerDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(initialWidth * 2, doubleDrawable.getIntrinsicWidth());
+        assertEquals(initialLeftPadding * 2, doubleDrawable.getLeftPadding());
+        assertEquals(initialRightPadding * 2, doubleDrawable.getRightPadding());
+        assertEquals(initialBottomPadding * 2, doubleDrawable.getBottomPadding());
+        assertEquals(initialTopPadding * 2, doubleDrawable.getTopPadding());
+        assertEquals(initialLayerInsetLeft * 2, doubleDrawable.getLayerInsetLeft(0));
+        assertEquals(initialLayerInsetRight * 2, doubleDrawable.getLayerInsetRight(0));
+        assertEquals(initialLayerInsetTop * 2, doubleDrawable.getLayerInsetTop(0));
+        assertEquals(initialLayerInsetBottom * 2, doubleDrawable.getLayerInsetBottom(0));
+        assertEquals(initialLayerWidth * 2, doubleDrawable.getLayerWidth(0));
+        assertEquals(initialLayerHeight * 2, doubleDrawable.getLayerHeight(0));
+
+        // Restore original configuration and metrics.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi);
+        final LayerDrawable origDrawable =
+                (LayerDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(initialWidth, origDrawable.getIntrinsicWidth());
+        assertEquals(initialLeftPadding, origDrawable.getLeftPadding());
+        assertEquals(initialRightPadding, origDrawable.getRightPadding());
+        assertEquals(initialBottomPadding, origDrawable.getBottomPadding());
+        assertEquals(initialTopPadding, origDrawable.getTopPadding());
+        assertEquals(initialLayerInsetLeft, origDrawable.getLayerInsetLeft(0));
+        assertEquals(initialLayerInsetRight, origDrawable.getLayerInsetRight(0));
+        assertEquals(initialLayerInsetTop, origDrawable.getLayerInsetTop(0));
+        assertEquals(initialLayerInsetBottom, origDrawable.getLayerInsetBottom(0));
+        assertEquals(initialLayerWidth, origDrawable.getLayerWidth(0));
+        assertEquals(initialLayerHeight, origDrawable.getLayerHeight(0));
+
+        // Ensure theme density is applied correctly.
+        final Theme t = res.newTheme();
+        halfDrawable.applyTheme(t);
+        assertEquals(initialWidth, halfDrawable.getIntrinsicWidth());
+        assertEquals(initialLeftPadding, halfDrawable.getLeftPadding());
+        assertEquals(initialRightPadding, halfDrawable.getRightPadding());
+        assertEquals(initialBottomPadding, halfDrawable.getBottomPadding());
+        assertEquals(initialTopPadding, halfDrawable.getTopPadding());
+        assertEquals(initialLayerInsetLeft, halfDrawable.getLayerInsetLeft(0));
+        assertEquals(initialLayerInsetRight, halfDrawable.getLayerInsetRight(0));
+        assertEquals(initialLayerInsetTop, halfDrawable.getLayerInsetTop(0));
+        assertEquals(initialLayerInsetBottom, halfDrawable.getLayerInsetBottom(0));
+        assertEquals(initialLayerWidth, halfDrawable.getLayerWidth(0));
+        assertEquals(initialLayerHeight, halfDrawable.getLayerHeight(0));
+        doubleDrawable.applyTheme(t);
+        assertEquals(initialWidth, doubleDrawable.getIntrinsicWidth());
+        assertEquals(initialLeftPadding, doubleDrawable.getLeftPadding());
+        assertEquals(initialRightPadding, doubleDrawable.getRightPadding());
+        assertEquals(initialBottomPadding, doubleDrawable.getBottomPadding());
+        assertEquals(initialTopPadding, doubleDrawable.getTopPadding());
+        assertEquals(initialLayerInsetLeft, doubleDrawable.getLayerInsetLeft(0));
+        assertEquals(initialLayerInsetRight, doubleDrawable.getLayerInsetRight(0));
+        assertEquals(initialLayerInsetTop, doubleDrawable.getLayerInsetTop(0));
+        assertEquals(initialLayerInsetBottom, doubleDrawable.getLayerInsetBottom(0));
+        assertEquals(initialLayerWidth, doubleDrawable.getLayerWidth(0));
+        assertEquals(initialLayerHeight, doubleDrawable.getLayerHeight(0));
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/LevelListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/LevelListDrawableTest.java
index 11186b0..4ef49c0 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/LevelListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/LevelListDrawableTest.java
@@ -31,7 +31,7 @@
 import android.test.InstrumentationTestCase;
 import android.util.Xml;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 
 public class LevelListDrawableTest extends InstrumentationTestCase {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
index 720397c..ba54b0c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -311,15 +311,23 @@
     }
 
     public void testInflate() throws XmlPullParserException, IOException {
-        final int width = 80;
-        final int height = 120;
-        final int[] COLOR = new int[width * height];
-        Bitmap bitmap = Bitmap.createBitmap(COLOR, width, height, Bitmap.Config.RGB_565);
-        NinePatchDrawable ninePatchDrawable =
-            new NinePatchDrawable(mResources, bitmap, new byte[1000], null, "TESTNAME");
+        int sourceWidth = 80;
+        int sourceHeight = 120;
+        int[] colors = new int[sourceWidth * sourceHeight];
+        Bitmap bitmap = Bitmap.createBitmap(
+                colors, sourceWidth, sourceHeight, Bitmap.Config.RGB_565);
+        NinePatchDrawable ninePatchDrawable = new NinePatchDrawable(
+                mResources, bitmap, new byte[1000], null, "TESTNAME");
 
-        assertEquals(height, ninePatchDrawable.getIntrinsicHeight());
-        assertEquals(width, ninePatchDrawable.getIntrinsicWidth());
+        int sourceDensity = bitmap.getDensity();
+        int targetDensity = mResources.getDisplayMetrics().densityDpi;
+        int targetWidth = DrawableTestUtils.scaleBitmapFromDensity(
+                sourceWidth, sourceDensity, targetDensity);
+        int targetHeight = DrawableTestUtils.scaleBitmapFromDensity(
+                sourceHeight, sourceDensity, targetDensity);
+        assertEquals(targetWidth, ninePatchDrawable.getIntrinsicWidth());
+        assertEquals(targetHeight, ninePatchDrawable.getIntrinsicHeight());
+
         XmlResourceParser parser = mResources.getXml(R.drawable.ninepatchdrawable);
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -329,8 +337,8 @@
         ninePatchDrawable.inflate(mResources, parser, attrs);
 
         assertTrue(ninePatchDrawable.getPaint().isDither());
-        assertTrue(height != ninePatchDrawable.getIntrinsicHeight());
-        assertTrue(width != ninePatchDrawable.getIntrinsicWidth());
+        assertTrue(sourceHeight != ninePatchDrawable.getIntrinsicHeight());
+        assertTrue(sourceWidth != ninePatchDrawable.getIntrinsicWidth());
     }
 
     public void testMutate() {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/PaintDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/PaintDrawableTest.java
index a440dab..fdb8f2f 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/PaintDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/PaintDrawableTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java
index b04433c..ab4fc0a 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java
@@ -16,12 +16,20 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.res.ColorStateList;
-import android.graphics.drawable.RippleDrawable;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.XmlResourceParser;
 import android.graphics.Color;
+import android.graphics.cts.R;
+import android.graphics.drawable.Drawable.ConstantState;
+import android.graphics.drawable.RippleDrawable;
 import android.test.AndroidTestCase;
+import android.util.Xml;
+
+import java.io.IOException;
 
 public class RippleDrawableTest extends AndroidTestCase {
     public void testConstructor() {
@@ -41,4 +49,44 @@
                 (RippleDrawable) getContext().getDrawable(R.drawable.rippledrawable_radius);
         assertEquals(10, drawable.getRadius());
     }
+
+    public void testPreloadDensity() throws XmlPullParserException, IOException {
+        final Resources res = getContext().getResources();
+        final int densityDpi = res.getConfiguration().densityDpi;
+
+        // Capture initial state at default density.
+        final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+                res, R.drawable.rippledrawable_radius);
+        final RippleDrawable preloadedDrawable = new RippleDrawable(
+                ColorStateList.valueOf(Color.BLACK), null, null);
+        preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
+        final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+        final int initialRadius = preloadedDrawable.getRadius();
+
+        // Set density to half of original. Unlike offsets, which are
+        // truncated, dimensions are rounded to the nearest pixel.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
+        final RippleDrawable halfDrawable =
+                (RippleDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(Math.round(initialRadius / 2f), halfDrawable.getRadius());
+
+        // Set density to double original.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
+        final RippleDrawable doubleDrawable =
+                (RippleDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(initialRadius * 2, doubleDrawable.getRadius());
+
+        // Restore original density.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi);
+        final RippleDrawable origDrawable =
+                (RippleDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(initialRadius, origDrawable.getRadius());
+
+        // Ensure theme density is applied correctly.
+        final Theme t = res.newTheme();
+        halfDrawable.applyTheme(t);
+        assertEquals(initialRadius, halfDrawable.getRadius());
+        doubleDrawable.applyTheme(t);
+        assertEquals(initialRadius, doubleDrawable.getRadius());
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/RotateDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/RotateDrawableTest.java
index cf25857..ccdedab 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/RotateDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/RotateDrawableTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
index b58e40f..e1f37b3 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -33,6 +33,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.ScaleDrawable;
+import android.os.Debug;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -296,6 +297,29 @@
         // expected, no Exception thrown out, test success
     }
 
+    public void testInitialLevel() throws XmlPullParserException, IOException {
+        ScaleDrawable dr = new ScaleDrawable(null, Gravity.CENTER, 1, 1);
+        Resources res = mContext.getResources();
+        XmlResourceParser parser = res.getXml(R.xml.scaledrawable_level);
+        AttributeSet attrs = DrawableTestUtils.getAttributeSet(parser, "scale_allattrs");
+
+        // Ensure that initial level is loaded from XML.
+        dr.inflate(res, parser, attrs);
+        assertEquals(5000, dr.getLevel());
+
+        dr.setLevel(0);
+        assertEquals(0, dr.getLevel());
+
+        // Ensure that initial level is propagated to constant state clones.
+        ScaleDrawable clone = (ScaleDrawable) dr.getConstantState().newDrawable(res);
+        assertEquals(5000, clone.getLevel());
+
+        // Ensure that current level is not tied to constant state.
+        dr.setLevel(1000);
+        assertEquals(1000, dr.getLevel());
+        assertEquals(5000, clone.getLevel());
+    }
+
     public void testOnLevelChange() {
         MockDrawable mockDrawable = new MockDrawable();
         MockScaleDrawable mockScaleDrawable = new MockScaleDrawable(
@@ -411,8 +435,7 @@
         XmlResourceParser parser = res.getXml(R.xml.scaledrawable);
         AttributeSet attrs = DrawableTestUtils.getAttributeSet(parser, "scale_allattrs");
         scaleDrawable.inflate(res, parser, attrs);
-        int bitmapSize = (int) Math.ceil(48.0 *
-                res.getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
+        final int bitmapSize = Math.round(48f * res.getDisplayMetrics().density);
         assertEquals(bitmapSize, scaleDrawable.getIntrinsicWidth());
         assertEquals(bitmapSize, scaleDrawable.getIntrinsicHeight());
 
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
index 5b3234e..042fb1b 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
@@ -34,7 +34,7 @@
 import android.util.AttributeSet;
 import android.util.Xml;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
index d55b91d..753db9b 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
@@ -22,19 +22,22 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.R.attr;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.StateListDrawable;
 import android.graphics.drawable.DrawableContainer.DrawableContainerState;
 import android.test.InstrumentationTestCase;
+import android.util.DisplayMetrics;
 import android.util.StateSet;
 import android.util.Xml;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 
 public class StateListDrawableTest extends InstrumentationTestCase {
@@ -153,6 +156,85 @@
         }
     }
 
+    public void testPreloadDensity() throws XmlPullParserException, IOException {
+        runPreloadDensityTestForDrawable(R.drawable.state_list_density, false);
+    }
+
+    public void testPreloadDensityConstantSize() throws XmlPullParserException, IOException {
+        runPreloadDensityTestForDrawable(R.drawable.state_list_density_constant_size, true);
+    }
+
+    private void runPreloadDensityTestForDrawable(int drawableResId, boolean isConstantSize)
+            throws XmlPullParserException, IOException {
+        final Configuration origConfig = new Configuration();
+        origConfig.setTo(mResources.getConfiguration());
+        final DisplayMetrics origMetrics = new DisplayMetrics();
+        origMetrics.setTo(mResources.getDisplayMetrics());
+
+        final Configuration halfConfig = new Configuration();
+        halfConfig.setTo(origConfig);
+        final DisplayMetrics halfMetrics = new DisplayMetrics();
+        halfMetrics.setTo(origMetrics);
+        halfConfig.densityDpi /= 2;
+        halfMetrics.densityDpi /= 2;
+        halfMetrics.density *= 2;
+
+        final Configuration doubleConfig = new Configuration();
+        doubleConfig.setTo(origConfig);
+        final DisplayMetrics doubleMetrics = new DisplayMetrics();
+        doubleMetrics.setTo(origMetrics);
+        doubleConfig.densityDpi *= 2;
+        doubleMetrics.densityDpi *= 2;
+        doubleMetrics.density /= 2;
+
+        final XmlResourceParser parser = getResourceParser(drawableResId);
+        final StateListDrawable preloadedDrawable = new StateListDrawable();
+        preloadedDrawable.inflate(mResources, parser, Xml.asAttributeSet(parser));
+        final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+        preloadedDrawable.selectDrawable(0);
+        final int tempWidth0 = preloadedDrawable.getIntrinsicWidth();
+        preloadedDrawable.selectDrawable(1);
+        final int tempWidth1 = preloadedDrawable.getIntrinsicWidth();
+
+        // Pick comparison widths based on constant size.
+        final int origWidth0;
+        final int origWidth1;
+        if (isConstantSize) {
+            origWidth0 = Math.max(tempWidth0, tempWidth1);
+            origWidth1 = origWidth0;
+        } else {
+            origWidth0 = tempWidth0;
+            origWidth1 = tempWidth1;
+        }
+
+        // Set density to half of original.
+        mResources.updateConfiguration(halfConfig, halfMetrics);
+        final StateListDrawable halfDrawable =
+                (StateListDrawable) preloadedConstantState.newDrawable(mResources);
+        halfDrawable.selectDrawable(0);
+        assertEquals(origWidth0 / 2, halfDrawable.getIntrinsicWidth());
+        halfDrawable.selectDrawable(1);
+        assertEquals(origWidth1 / 2, halfDrawable.getIntrinsicWidth());
+
+        // Restore original configuration and metrics.
+        mResources.updateConfiguration(origConfig, origMetrics);
+        final StateListDrawable origDrawable =
+                (StateListDrawable) preloadedConstantState.newDrawable(mResources);
+        origDrawable.selectDrawable(0);
+        assertEquals(origWidth0, origDrawable.getIntrinsicWidth());
+        origDrawable.selectDrawable(1);
+        assertEquals(origWidth1, origDrawable.getIntrinsicWidth());
+
+        // Set density to double original.
+        mResources.updateConfiguration(doubleConfig, doubleMetrics);
+        final StateListDrawable doubleDrawable =
+                (StateListDrawable) preloadedConstantState.newDrawable(mResources);
+        doubleDrawable.selectDrawable(0);
+        assertEquals(origWidth0 * 2, doubleDrawable.getIntrinsicWidth());
+        doubleDrawable.selectDrawable(1);
+        assertEquals(origWidth1 * 2, doubleDrawable.getIntrinsicWidth());
+    }
+
     public void testInflate() throws XmlPullParserException, IOException {
         XmlResourceParser parser = getResourceParser(R.xml.selector_correct);
 
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
index d7becc6..52bef55 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
@@ -32,7 +32,7 @@
 import android.test.AndroidTestCase;
 import android.view.Gravity;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 @TargetApi(21)
 public class ThemedDrawableTest extends AndroidTestCase {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/TransitionDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/TransitionDrawableTest.java
index f2a22a2..c0ef1be 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/TransitionDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/TransitionDrawableTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics.drawable.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import android.content.res.Resources;
 import android.graphics.Bitmap;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
index fdc7b7a..8944d63 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
@@ -16,33 +16,34 @@
 
 package android.graphics.drawable.cts;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.ColorFilter;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.VectorDrawable;
+import android.graphics.cts.R;
 import android.graphics.drawable.Drawable.ConstantState;
+import android.graphics.drawable.VectorDrawable;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
 
-import com.android.cts.graphics.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 
 public class VectorDrawableTest extends AndroidTestCase {
-    private static final String LOGTAG = VectorDrawableTest.class.getSimpleName();
-    private int[] mIconResIds = new int[] {
+    private static final String LOGTAG = "VectorDrawableTest";
+
+    private static final int[] ICON_RES_IDS = new int[] {
             R.drawable.vector_icon_create,
             R.drawable.vector_icon_delete,
             R.drawable.vector_icon_heart,
@@ -68,9 +69,11 @@
             R.drawable.vector_icon_stroke_3,
             R.drawable.vector_icon_scale_1,
             R.drawable.vector_icon_scale_2,
+            R.drawable.vector_icon_implicit_lineto,
+            R.drawable.vector_icon_arcto,
     };
 
-    private int[] mGoldenImages = new int[] {
+    private static final int[] GOLDEN_IMAGES = new int[] {
             R.drawable.vector_icon_create_golden,
             R.drawable.vector_icon_delete_golden,
             R.drawable.vector_icon_heart_golden,
@@ -96,6 +99,22 @@
             R.drawable.vector_icon_stroke_3_golden,
             R.drawable.vector_icon_scale_1_golden,
             R.drawable.vector_icon_scale_2_golden,
+            R.drawable.vector_icon_implicit_lineto_golden,
+            R.drawable.vector_icon_arcto_golden,
+    };
+
+    private static final int[] STATEFUL_RES_IDS = new int[] {
+            R.drawable.vector_icon_state_list
+    };
+
+    private static final int[][] STATEFUL_GOLDEN_IMAGES = new int[][] {
+            { R.drawable.vector_icon_state_list_golden },
+            { R.drawable.vector_icon_state_list_golden_pressed }
+    };
+
+    private static final int[][] STATEFUL_STATE_SETS = new int[][] {
+            {},
+            { android.R.attr.state_pressed }
     };
 
     private static final int IMAGE_WIDTH = 64;
@@ -104,7 +123,7 @@
     // exactly with the golden image.
     // We can increase the threshold if the Skia is drawing with some variance
     // on different devices. So far, the tests show they are matching correctly.
-    private static final float PIXEL_ERROR_THRESHOLD = 0.02f;
+    private static final float PIXEL_ERROR_THRESHOLD = 0.03f;
     private static final float PIXEL_ERROR_COUNT_THRESHOLD = 0.005f;
 
     private static final boolean DBG_DUMP_PNG = false;
@@ -128,19 +147,27 @@
         mResources = mContext.getResources();
     }
 
-    public void testSimpleVectorDrawables() throws Exception {
-        verifyVectorDrawables(mIconResIds, mGoldenImages, 0);
+    public void testSimpleVectorDrawables() throws XmlPullParserException, IOException {
+        verifyVectorDrawables(ICON_RES_IDS, GOLDEN_IMAGES, null);
     }
 
-    private void verifyVectorDrawables(int[] resIds, int[] goldenImages, float fraction) throws Exception {
+    public void testColorStateList() throws XmlPullParserException, IOException {
+        for (int i = 0; i < STATEFUL_STATE_SETS.length; i++) {
+            verifyVectorDrawables(
+                    STATEFUL_RES_IDS, STATEFUL_GOLDEN_IMAGES[i], STATEFUL_STATE_SETS[i]);
+        }
+    }
+
+    private void verifyVectorDrawables(int[] resIds, int[] goldenImages, int[] stateSet)
+            throws XmlPullParserException, IOException {
         for (int i = 0; i < resIds.length; i++) {
             // Setup VectorDrawable from xml file and draw into the bitmap.
             XmlPullParser parser = mResources.getXml(resIds[i]);
             AttributeSet attrs = Xml.asAttributeSet(parser);
 
             int type;
-            while ((type=parser.next()) != XmlPullParser.START_TAG &&
-                    type != XmlPullParser.END_DOCUMENT) {
+            while ((type=parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
                 // Empty loop
             }
 
@@ -150,11 +177,15 @@
 
             mVectorDrawable.inflate(mResources, parser, attrs);
 
+            if (stateSet != null) {
+                mVectorDrawable.setState(stateSet);
+            }
+
             mBitmap.eraseColor(0);
             mVectorDrawable.draw(mCanvas);
 
             if (DBG_DUMP_PNG) {
-                saveVectorDrawableIntoPNG(mBitmap, resIds, i);
+                saveVectorDrawableIntoPNG(mBitmap, resIds, i, stateSet);
             } else {
                 // Start to compare
                 Bitmap golden = BitmapFactory.decodeResource(mResources, goldenImages[i]);
@@ -164,7 +195,8 @@
     }
 
     // This is only for debugging or golden image (re)generation purpose.
-    private void saveVectorDrawableIntoPNG(Bitmap bitmap, int[] resIds, int index) throws IOException {
+    private void saveVectorDrawableIntoPNG(Bitmap bitmap, int[] resIds, int index, int[] stateSet)
+            throws IOException {
         // Save the image to the disk.
         FileOutputStream out = null;
         try {
@@ -177,7 +209,8 @@
             File originalFile = new File(originalFilePath);
             String fileFullName = originalFile.getName();
             String fileTitle = fileFullName.substring(0, fileFullName.lastIndexOf("."));
-            String outputFilename = outputFolder + fileTitle + "_golden.png";
+            String stateSetTitle = getTitleForStateSet(stateSet);
+            String outputFilename = outputFolder + fileTitle + "_golden" + stateSetTitle + ".png";
             File outputFile = new File(outputFilename);
             if (!outputFile.exists()) {
                 outputFile.createNewFile();
@@ -195,6 +228,38 @@
         }
     }
 
+    /**
+     * Generates an underline-delimited list of states in a given state set.
+     * <p>
+     * For example, the array {@code {R.attr.state_pressed}} would return
+     * {@code "_pressed"}.
+     *
+     * @param stateSet a state set
+     * @return a string representing the state set, or the empty string if the
+     *         state set is empty or {@code null}
+     */
+    private String getTitleForStateSet(int[] stateSet) {
+        if (stateSet == null || stateSet.length == 0) {
+            return "";
+        }
+
+        final Resources res = getContext().getResources();
+        final StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < stateSet.length; i++) {
+            builder.append('_');
+
+            final String state = res.getResourceName(stateSet[i]);
+            final int stateIndex = state.indexOf("state_");
+            if (stateIndex >= 0) {
+                builder.append(state.substring(stateIndex + 6));
+            } else {
+                builder.append(stateSet[i]);
+            }
+        }
+
+        return builder.toString();
+    }
+
     private void compareImages(Bitmap ideal, Bitmap given, String filename) {
         int idealWidth = ideal.getWidth();
         int idealHeight = ideal.getHeight();
@@ -299,4 +364,43 @@
 
         assertEquals(filter, vectorDrawable.getColorFilter());
     }
+
+    public void testPreloadDensity() throws XmlPullParserException, IOException {
+        final Resources res = mResources;
+        final int densityDpi = res.getConfiguration().densityDpi;
+
+        // Capture initial state at default density.
+        final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+                res, R.drawable.vector_density);
+        final VectorDrawable preloadedDrawable = new VectorDrawable();
+        preloadedDrawable.inflate(mResources, parser, Xml.asAttributeSet(parser));
+        final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+        final int origWidth = preloadedDrawable.getIntrinsicWidth();
+
+        // Set density to half of original. Unlike offsets, which are
+        // truncated, dimensions are rounded to the nearest pixel.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
+        final VectorDrawable halfDrawable =
+                (VectorDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
+
+        // Set density to double original.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
+        final VectorDrawable doubleDrawable =
+                (VectorDrawable) preloadedConstantState.newDrawable(res);
+        assertEquals(origWidth * 2, doubleDrawable.getIntrinsicWidth());
+
+        // Restore original density.
+        DrawableTestUtils.setResourcesDensity(res, densityDpi);
+        final VectorDrawable origDrawable =
+                (VectorDrawable) preloadedConstantState.newDrawable();
+        assertEquals(origWidth, origDrawable.getIntrinsicWidth());
+
+        // Ensure theme density is applied correctly.
+        final Theme t = res.newTheme();
+        halfDrawable.applyTheme(t);
+        assertEquals(origWidth, halfDrawable.getIntrinsicWidth());
+        doubleDrawable.applyTheme(t);
+        assertEquals(origWidth, doubleDrawable.getIntrinsicWidth());
+    }
 }
diff --git a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureCtsActivity.java b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureCtsActivity.java
index 533508a..bade5a8 100644
--- a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureCtsActivity.java
+++ b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureCtsActivity.java
@@ -15,7 +15,7 @@
  */
 package android.opengl.cts;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import android.app.Activity;
 import android.content.Intent;
diff --git a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureLoader.java b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureLoader.java
index 1524f99..3a2e00f 100644
--- a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureLoader.java
+++ b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureLoader.java
@@ -21,7 +21,7 @@
 import java.nio.ByteOrder;
 import java.util.HashMap;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import android.app.Activity;
 import android.content.res.AssetFileDescriptor;
diff --git a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureSurfaceView.java b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureSurfaceView.java
index 84aae10..9437c58 100644
--- a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureSurfaceView.java
+++ b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureSurfaceView.java
@@ -27,7 +27,7 @@
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
 
-import com.android.cts.graphics.R;
+import android.graphics.cts.R;
 
 import android.content.Context;
 import android.content.res.Resources;
diff --git a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java
index c153712..09902df 100644
--- a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java
@@ -24,13 +24,13 @@
 public class CompressedTextureTest extends ActivityInstrumentationTestCase2<CompressedTextureCtsActivity> {
 
     public CompressedTextureTest() {
-        super("com.android.cts.graphics", CompressedTextureCtsActivity.class);
+        super("android.graphics.cts", CompressedTextureCtsActivity.class);
     }
 
     private void launchTest(String format) throws Exception {
         Bundle extras = new Bundle();
         extras.putString("TextureFormat", format);
-        CompressedTextureCtsActivity activity = launchActivity("com.android.cts.graphics",
+        CompressedTextureCtsActivity activity = launchActivity("android.graphics.cts",
                 CompressedTextureCtsActivity.class, extras);
         activity.finish();
         assertTrue(activity.getPassed());
diff --git a/tests/tests/graphics/src/android/opengl/cts/EglConfigTest.java b/tests/tests/graphics/src/android/opengl/cts/EglConfigTest.java
index 14c8e10..33e82043 100644
--- a/tests/tests/graphics/src/android/opengl/cts/EglConfigTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/EglConfigTest.java
@@ -37,7 +37,7 @@
     private Instrumentation mInstrumentation;
 
     public EglConfigTest() {
-        super("com.android.cts.graphics", EglConfigCtsActivity.class);
+        super("android.graphics.cts", EglConfigCtsActivity.class);
     }
 
     @Override
@@ -60,7 +60,7 @@
             Bundle extras = new Bundle();
             extras.putInt(EglConfigCtsActivity.CONFIG_ID_EXTRA, configId);
             extras.putInt(EglConfigCtsActivity.CONTEXT_CLIENT_VERSION_EXTRA, contextClientVersion);
-            EglConfigCtsActivity activity = launchActivity("com.android.cts.graphics",
+            EglConfigCtsActivity activity = launchActivity("android.graphics.cts",
                     EglConfigCtsActivity.class, extras);
             activity.waitToFinishDrawing();
             activity.finish();
diff --git a/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewTest.java b/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewTest.java
index 87995fb..f603419 100644
--- a/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewTest.java
@@ -41,7 +41,7 @@
     private GLSurfaceViewCtsActivity mActivity;
 
     public GLSurfaceViewTest() {
-        super("com.android.cts.graphics", GLSurfaceViewCtsActivity.class);
+        super("android.graphics.cts", GLSurfaceViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
index 28ac5c0..c991b6f 100644
--- a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
@@ -48,7 +48,7 @@
     private OpenGlEsVersionCtsActivity mActivity;
 
     public OpenGlEsVersionTest() {
-        super("com.android.cts.graphics", OpenGlEsVersionCtsActivity.class);
+        super("android.graphics.cts", OpenGlEsVersionCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/graphics2/Android.mk b/tests/tests/graphics2/Android.mk
index a3cdafa..566b6a32b 100644
--- a/tests/tests/graphics2/Android.mk
+++ b/tests/tests/graphics2/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_PACKAGE_NAME := CtsGraphics2TestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_INSTRUMENTATION_FOR :=
 
 LOCAL_SDK_VERSION := current
diff --git a/tests/tests/graphics2/AndroidManifest.xml b/tests/tests/graphics2/AndroidManifest.xml
index 67557ad..be7a985 100644
--- a/tests/tests/graphics2/AndroidManifest.xml
+++ b/tests/tests/graphics2/AndroidManifest.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.graphics2"
+    package="android.graphics2.cts"
     android:versionCode="1"
     android:versionName="1.0" >
 
@@ -23,7 +23,7 @@
     <uses-feature android:name="android.hardware.camera" />
 
     <instrumentation
-        android:targetPackage="com.android.cts.graphics2"
+        android:targetPackage="android.graphics2.cts"
         android:name="android.support.test.runner.AndroidJUnitRunner" >
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/graphics2/AndroidTest.xml b/tests/tests/graphics2/AndroidTest.xml
new file mode 100644
index 0000000..2f9961b
--- /dev/null
+++ b/tests/tests/graphics2/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Graphics test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsGraphics2TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.graphics2.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/hardware/Android.mk b/tests/tests/hardware/Android.mk
index 07d5de9..df493d6 100644
--- a/tests/tests/hardware/Android.mk
+++ b/tests/tests/hardware/Android.mk
@@ -22,7 +22,9 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util
 
 LOCAL_SDK_VERSION := current
 
@@ -36,8 +38,6 @@
     src/android/hardware/cts/SensorTest.java \
     src/android/hardware/cts/SensorManagerStaticTest.java
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil
-
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 
@@ -47,16 +47,21 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner mockito-target android-ex-camera2
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner mockito-target android-ex-camera2
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsHardwareTestCases
 
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
 LOCAL_SDK_VERSION := current
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-cts_runtime_hint := 120
-
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/hardware/AndroidManifest.xml b/tests/tests/hardware/AndroidManifest.xml
index 031b19e..34a1475 100644
--- a/tests/tests/hardware/AndroidManifest.xml
+++ b/tests/tests/hardware/AndroidManifest.xml
@@ -72,6 +72,9 @@
             android:process=":camera2ActivityProcess">
         </activity>
 
+        <activity android:name="android.hardware.input.cts.InputCtsActivity"
+            android:label="InputCtsActivity" />
+
         <activity android:name="android.hardware.cts.FingerprintTestActivity"
             android:label="FingerprintTestActivity">
         </activity>
diff --git a/tests/tests/hardware/AndroidTest.xml b/tests/tests/hardware/AndroidTest.xml
index 4ddf28c..a970b95 100644
--- a/tests/tests/hardware/AndroidTest.xml
+++ b/tests/tests/hardware/AndroidTest.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,10 +12,20 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Base config for Sensor CTS tests. Put SensorService in restricted mode">
-    <include name="common-config" />
+<configuration description="Config for CTS Hardware test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsHardwareTestCases.apk" />
+    </target_preparer>
     <!-- Put SensorService in restricted mode so that only CTS tests will be able to get access to
     sensors -->
-    <option name="run-command:run-command" value="dumpsys sensorservice restrict .cts." />
-    <option name="run-command:teardown-command" value="dumpsys sensorservice enable" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="dumpsys sensorservice restrict .cts." />
+        <option name="teardown-command" value="dumpsys sensorservice enable" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.cts.hardware" />
+    </test>
+
 </configuration>
diff --git a/tests/tests/hardware/OldAndroidTest.xml b/tests/tests/hardware/OldAndroidTest.xml
new file mode 100644
index 0000000..4ddf28c
--- /dev/null
+++ b/tests/tests/hardware/OldAndroidTest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Base config for Sensor CTS tests. Put SensorService in restricted mode">
+    <include name="common-config" />
+    <!-- Put SensorService in restricted mode so that only CTS tests will be able to get access to
+    sensors -->
+    <option name="run-command:run-command" value="dumpsys sensorservice restrict .cts." />
+    <option name="run-command:teardown-command" value="dumpsys sensorservice enable" />
+</configuration>
diff --git a/tests/tests/hardware/res/raw/gamepad_press_a.json b/tests/tests/hardware/res/raw/gamepad_press_a.json
new file mode 100644
index 0000000..ff3ca4f
--- /dev/null
+++ b/tests/tests/hardware/res/raw/gamepad_press_a.json
@@ -0,0 +1,39 @@
+{
+    "id": 1,
+    "command": "register",
+    "name": "Odie (Test)",
+    "vid": 0x18d1,
+    "pid": 0x2c40,
+    "descriptor": [0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x05, 0x09, 0x0a, 0x01, 0x00,
+        0x0a, 0x02, 0x00, 0x0a, 0x04, 0x00, 0x0a, 0x05, 0x00, 0x0a, 0x07, 0x00, 0x0a, 0x08, 0x00,
+        0x0a, 0x0e, 0x00, 0x0a, 0x0f, 0x00, 0x0a, 0x0d, 0x00, 0x05, 0x0c, 0x0a, 0x24, 0x02, 0x0a,
+        0x23, 0x02, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x0b, 0x81, 0x02, 0x75, 0x01, 0x95,
+        0x01, 0x81, 0x03, 0x05, 0x01, 0x75, 0x04, 0x95, 0x01, 0x25, 0x07, 0x46, 0x3b, 0x01, 0x66,
+        0x14, 0x00, 0x09, 0x39, 0x81, 0x42, 0x66, 0x00, 0x00, 0x09, 0x01, 0xa1, 0x00, 0x09, 0x30,
+        0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x05, 0x02, 0x09, 0xc5, 0x09, 0xc4, 0x15, 0x00, 0x26,
+        0xff, 0x00, 0x35, 0x00, 0x46, 0xff, 0x00, 0x75, 0x08, 0x95, 0x06, 0x81, 0x02, 0xc0, 0x85,
+        0x02, 0x05, 0x08, 0x0a, 0x01, 0x00, 0x0a, 0x02, 0x00, 0x0a, 0x03, 0x00, 0x0a, 0x04, 0x00,
+        0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x04, 0x91, 0x02, 0x75, 0x04, 0x95, 0x01, 0x91,
+        0x03, 0xc0, 0x05, 0x0c, 0x09, 0x01, 0xa1, 0x01, 0x85, 0x03, 0x05, 0x01, 0x09, 0x06, 0xa1,
+        0x02, 0x05, 0x06, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x81,
+        0x02, 0x06, 0xbc, 0xff, 0x0a, 0xad, 0xbd, 0x75, 0x08, 0x95, 0x06, 0x81, 0x02, 0xc0, 0xc0],
+    "report": [0x01, 0x00, 0x80, 0x90, 0x80, 0x7f, 0x73, 0x00, 0x00]
+}
+
+{
+    "id": 1,
+    "command": "report",
+    "report": [0x01, 0x01, 0x80, 0x90, 0x80, 0x7f, 0x73, 0x00, 0x00]
+}
+
+{
+    "id": 1,
+    "command": "delay",
+    "duration": 10
+}
+
+{
+    "id": 1,
+    "command": "report",
+    "report": [0x01, 0x00, 0x80, 0x90, 0x80, 0x7f, 0x73, 0x00, 0x00]
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
index 9d36f37..694c61f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
@@ -27,8 +27,6 @@
 import android.hardware.cts.helpers.TestSensorEvent;
 import android.util.SparseIntArray;
 
-import com.android.cts.util.StatisticsUtils;
-
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/InputCallback.java b/tests/tests/hardware/src/android/hardware/input/cts/InputCallback.java
new file mode 100644
index 0000000..accdcaf
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/cts/InputCallback.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input.cts;
+
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public interface InputCallback {
+    public void onKeyEvent(KeyEvent ev);
+    public void onMotionEvent(MotionEvent ev);
+}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/InputCtsActivity.java b/tests/tests/hardware/src/android/hardware/input/cts/InputCtsActivity.java
new file mode 100644
index 0000000..b16cadb
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/cts/InputCtsActivity.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input.cts;
+
+import android.app.Activity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class InputCtsActivity extends Activity {
+    private InputCallback mInputCallback;
+
+    @Override
+    public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+        if (mInputCallback != null) {
+            mInputCallback.onMotionEvent(ev);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (mInputCallback != null) {
+            mInputCallback.onMotionEvent(ev);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean dispatchTrackballEvent(MotionEvent ev) {
+        if (mInputCallback != null) {
+            mInputCallback.onMotionEvent(ev);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent ev) {
+        if (mInputCallback != null) {
+            mInputCallback.onKeyEvent(ev);
+        }
+        return true;
+    }
+
+    public void setInputCallback(InputCallback callback) {
+        mInputCallback = callback;
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/GamepadTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/GamepadTestCase.java
new file mode 100644
index 0000000..92fba12
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/GamepadTestCase.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input.cts.tests;
+
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.io.Writer;
+import java.util.List;
+
+import com.android.cts.hardware.R;
+
+public class GamepadTestCase extends InputTestCase {
+    private static final String TAG = "GamepadTests";
+
+    public void testButtonA() throws Exception {
+        sendHidCommands(R.raw.gamepad_press_a);
+        assertReceivedKeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BUTTON_A);
+        assertReceivedKeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BUTTON_A);
+        assertNoMoreEvents();
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
new file mode 100644
index 0000000..fba5f51
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input.cts.tests;
+
+import android.app.UiAutomation;
+import android.hardware.input.cts.InputCtsActivity;
+import android.hardware.input.cts.InputCallback;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.List;
+import java.util.UUID;
+
+public class InputTestCase extends ActivityInstrumentationTestCase2<InputCtsActivity> {
+    private static final String TAG = "InputTestCase";
+    private static final String HID_EXECUTABLE = "hid";
+    private static final int SHELL_UID = 2000;
+    private static final String[] KEY_ACTIONS = {"DOWN", "UP", "MULTIPLE"};
+
+    private File mFifo;
+    private Writer mWriter;
+
+    private BlockingQueue<KeyEvent> mKeys;
+    private BlockingQueue<MotionEvent> mMotions;
+    private InputListener mInputListener;
+
+    public InputTestCase() {
+        super(InputCtsActivity.class);
+        mKeys = new LinkedBlockingQueue<KeyEvent>();
+        mMotions = new LinkedBlockingQueue<MotionEvent>();
+        mInputListener = new InputListener();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mFifo = setupFifo();
+        clearKeys();
+        clearMotions();
+        getActivity().setInputCallback(mInputListener);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mFifo != null) {
+            mFifo.delete();
+            mFifo = null;
+        }
+        closeQuietly(mWriter);
+        mWriter = null;
+        super.tearDown();
+    }
+
+    /**
+     * Sends the HID commands designated by the given resource id.
+     * The commands must be in the format expected by the `hid` shell command.
+     *
+     * @param id The resource id from which to load the HID commands. This must be a "raw"
+     * resource.
+     */
+    public void sendHidCommands(int id) {
+        try {
+            Writer w = getWriter();
+            w.write(getEvents(id));
+            w.flush();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Asserts that the application received a {@link android.view.KeyEvent} with the given action
+     * and keycode.
+     *
+     * If other KeyEvents are received by the application prior to the expected KeyEvent, or no
+     * KeyEvents are received within a reasonable amount of time, then this will throw an
+     * AssertionFailedError.
+     *
+     * @param action The action to expect on the next KeyEvent
+     * (e.g. {@link android.view.KeyEvent#ACTION_DOWN}).
+     * @param keyCode The expected key code of the next KeyEvent.
+     */
+    public void assertReceivedKeyEvent(int action, int keyCode) {
+        KeyEvent k = waitForKey();
+        if (k == null) {
+            fail("Timed out waiting for " + KeyEvent.keyCodeToString(keyCode)
+                    + " with action " + KEY_ACTIONS[action]);
+            return;
+        }
+        assertEquals(action, k.getAction());
+        assertEquals(keyCode, k.getKeyCode());
+    }
+
+    /**
+     * Asserts that no more events have been received by the application.
+     *
+     * If any more events have been received by the application, this throws an
+     * AssertionFailedError.
+     */
+    public void assertNoMoreEvents() {
+        KeyEvent key;
+        MotionEvent motion;
+        if ((key = mKeys.poll()) != null) {
+            fail("Extraneous key events generated: " + key);
+        }
+        if ((motion = mMotions.poll()) != null) {
+            fail("Extraneous motion events generated: " + motion);
+        }
+    }
+
+    private KeyEvent waitForKey() {
+        try {
+            return mKeys.poll(1, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            return null;
+        }
+    }
+
+    private void clearKeys() {
+        mKeys.clear();
+    }
+
+    private void clearMotions() {
+        mMotions.clear();
+    }
+
+    private File setupFifo() throws ErrnoException {
+        File dir = getActivity().getCacheDir();
+        String filename = dir.getAbsolutePath() + File.separator +  UUID.randomUUID().toString();
+        Os.mkfifo(filename, 0666);
+        File f = new File(filename);
+        return f;
+    }
+
+    private Writer getWriter() throws IOException {
+        if (mWriter == null) {
+            UiAutomation ui = getInstrumentation().getUiAutomation();
+            ui.executeShellCommand("hid " + mFifo.getAbsolutePath());
+            mWriter = new FileWriter(mFifo);
+        }
+        return mWriter;
+    }
+
+    private String getEvents(int id) throws IOException {
+        InputStream is =
+            getInstrumentation().getTargetContext().getResources().openRawResource(id);
+        return readFully(is);
+    }
+
+
+    private static void closeQuietly(AutoCloseable closeable) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (RuntimeException rethrown) {
+                throw rethrown;
+            } catch (Exception ignored) { }
+        }
+    }
+
+    private static String readFully(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        int read = 0;
+        byte[] buffer = new byte[1024];
+        while ((read = is.read(buffer)) >= 0) {
+            baos.write(buffer, 0, read);
+        }
+        return baos.toString();
+    }
+
+    private class InputListener implements InputCallback {
+        public void onKeyEvent(KeyEvent ev) {
+            boolean done = false;
+            do {
+                try {
+                    mKeys.put(new KeyEvent(ev));
+                    done = true;
+                } catch (InterruptedException ignore) { }
+            } while (!done);
+        }
+
+        public void onMotionEvent(MotionEvent ev) {
+            boolean done = false;
+            do {
+                try {
+                    mMotions.put(MotionEvent.obtain(ev));
+                    done = true;
+                } catch (InterruptedException ignore) { }
+            } while (!done);
+        }
+    }
+}
diff --git a/tests/tests/icu/Android.mk b/tests/tests/icu/Android.mk
new file mode 100644
index 0000000..12cd7b0
--- /dev/null
+++ b/tests/tests/icu/Android.mk
@@ -0,0 +1,66 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# The aim of this package is to run tests against the default packaging of ICU as a standalone
+# java library, and not as the implementation in use by the current android system. For this
+# reason, all the required ICU resources are included into the APK by the following rules.
+# icu4j contains ICU's implementation classes, icu4j-tests contains the test classes,
+# and icudata/icutzdata contain data files and timezone data files respectively.
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test icu4j icu4j-tests \
+	icu4j-icudata icu4j-icutzdata icu4j-testdata
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_PACKAGE_NAME := CtsIcuTestCases
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
+
+# The CTS framework has it's own logic for generating XML files based on scanning the source
+# for test methods and classes. Since the classes that we are testing are not actually in this
+# package we must provide an alternative. Here we define a specially crafted XML file which
+# conforms to what CTS and particularly, the cts-tradefed tool understands. This file contains
+# lists of classes in ICU4J that we know are used in libcore and should be tested as part of CTS.
+# The following rule uses the Android CoPy (ACP) tool to copy this file to where it is expected.
+
+ifeq ($(TARGET_ARCH),arm64)
+	LOCAL_ARCH := arm
+else ifeq ($(TARGET_ARCH),mips64)
+	LOCAL_ARCH := mips
+else ifeq ($(TARGET_ARCH),x86_64)
+	LOCAL_ARCH := x86
+else
+	LOCAL_ARCH := $(TARGET_ARCH)
+endif
+
+cts_package_xml := $(CTS_TESTCASES_OUT)/CtsIcuTestCases.xml
+$(cts_package_xml): $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/package.apk | $(ACP)
+	$(ACP) -fp cts/tests/tests/icu/CtsIcuTestCases_$(LOCAL_ARCH).xml $@
diff --git a/tests/tests/icu/AndroidManifest.xml b/tests/tests/icu/AndroidManifest.xml
new file mode 100644
index 0000000..7d99c0a
--- /dev/null
+++ b/tests/tests/icu/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.icu.cts">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.icu.cts.IcuTestRunner"
+                     android:targetPackage="android.icu.cts"
+                     android:label="ICU4J library tests."/>
+</manifest>
diff --git a/tests/tests/icu/AndroidTest.xml b/tests/tests/icu/AndroidTest.xml
new file mode 100644
index 0000000..299956d
--- /dev/null
+++ b/tests/tests/icu/AndroidTest.xml
@@ -0,0 +1,24 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS ICU test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsIcuTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="runner" value="android.icu.cts.IcuTestRunner" /><!-- override AJUR -->
+        <option name="package" value="android.icu.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/icu/CtsIcuTestCases_arm.xml b/tests/tests/icu/CtsIcuTestCases_arm.xml
new file mode 100644
index 0000000..96f0701
--- /dev/null
+++ b/tests/tests/icu/CtsIcuTestCases_arm.xml
@@ -0,0 +1,563 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<TestPackage AndroidFramework="Android 1.0"
+             appNameSpace="android.icu.cts"
+             appPackageName="com.ibm.icu.dev.test"
+             name="CtsIcuTestCases"
+             runner=".IcuTestRunner"
+             version="1.0">
+
+    <!--
+    ICU tests are run against ICU as a standalone library so the package names are com.ibm.icu.*.
+    Each test class has one dummy method called "run-everything". This is because CTS will not try
+    to run a class if there is no known test method on it. The IcuTestRunner is aware of this and
+    pretends to run the method "run-everything", but actually dispatches the run to ICU's own test
+    runner. If the test is successful, a return code of 0 from ICU's test runner will be detected
+    and we report that the "run-everything" method passed. If there is any failure in the class,
+    we report that "run-everything" failed and print out the detailed method by method listing
+    from ICU about what actually failed, as the stack trace for the failure in "run-everything".
+    -->
+
+    <TestSuite name="com">
+        <TestSuite name="ibm">
+            <TestSuite name="icu">
+                <TestSuite name="dev">
+                    <TestSuite name="test">
+                        <TestSuite name="translit">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="PrettyPrinterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TransliteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RegexUtilitiesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ReplaceableTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RoundTripTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="AnyScriptTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ErrorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UnicodeMapTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="CompoundTransliteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestUnicodeProperty">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="util">
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="ICUResourceBundleCollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ULocaleCollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="GenderInfoTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="BytesTrieTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="LocaleDataTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CurrencyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RegionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ULocaleTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="StringTokenizerTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CharsTrieTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CompactArrayTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="LocaleBuilderTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TrieMapTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ICUServiceThreadTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ICUBinaryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ICUResourceBundleTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="DebugUtilitiesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="SimplePatternFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="LocaleMatcherTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UtilityTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="Trie2Test">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ICUServiceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="VersionInfoTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="LocalePriorityListTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TrieTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TextTrieMapTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="search">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="SearchTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="collator">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="LotusCollationKoreanTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationTurkishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationMiscTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationAPITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationServiceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="AlphabeticIndexTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationFinnishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationDummyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationRegressionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationChineseTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationGermanTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="G7CollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationSpanishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="CollationCreationMethodTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UCAConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationKanaTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationFrenchTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationIteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationThaiTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationFrozenMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationThreadTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationEnglishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CollationCurrencyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="format">
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="GlobalizationPreferencesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RbnfLenientScannerTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="PluralRangesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="SelectFormatUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="PluralRulesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="RelativeDateTimeFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RBNFParseTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TimeUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CompactDecimalFormatTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RbnfRoundTripTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RbnfTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="SelectFormatAPITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="PluralFormatTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="BigNumberFormatTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ListFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="DateTimeGeneratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="NumberFormatSpecificationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="MeasureUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="ScientificNumberFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="PluralFormatUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="compression">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ExhaustiveTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="DecompressionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="text">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="SpoofCheckerTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="iterator">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestUCharacterIterator">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="duration">
+                            <TestSuite name="languages">
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_en">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_es">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_fr">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_he_IL">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_hi">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_it">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_ja">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_ko">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_zh_Hans">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_zh_Hans_SG">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_zh_Hant">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="armeabi-v7a arm64-v8a"
+                                          name="Test_zh_Hant_HK">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                            </TestSuite>
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="ResourceBasedPeriodFormatterDataServiceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ICUDurationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="PeriodBuilderFactoryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="PeriodBuilderTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="PeriodTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="DataReadWriteTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RegressionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="rbbi">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RBBITestExtended">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="SimpleBITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="BreakIteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RBBITestMonkey">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="RBBITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="BreakIteratorRegTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="lang">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestUScript">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UPropertyAliasesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UTF16Test">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UCharacterCategoryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UnicodeSetStringSpanTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UnicodeSetTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UCharacterCaseTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UCharacterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UCharacterThreadTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UCharacterSurrogateTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestUScriptRun">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UCharacterDirectionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="charsetdet">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestCharsetDetector">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="normalizer">
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="TestDeprecatedNormalizerAPI">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="NormalizationMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestCanonicalIterator">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="BasicTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="NormalizerRegressionTests">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="UTS46Test">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a"
+                                      name="UnicodeNormalizerConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="bidi">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="BidiTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="BiDiConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="shaping">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="ArabicShapingRegTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="stringprep">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestStringPrep">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="IDNAConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestIDNA">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestStringPrepProfiles">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestIDNARef">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="timezone">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TimeZoneTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TimeZoneRuleTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TimeZoneRegression">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TimeZoneBoundaryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TimeZoneOffsetLocalTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="bigdec">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="DiagBigDecimal">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="calendar">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="CalendarTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="AstroTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="HolidayTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="timescale">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TimeScaleMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TimeScaleAPITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TimeScaleDataTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="charset">
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestSelection">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="armeabi-v7a arm64-v8a" name="TestCharset">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestCase abis="armeabi-v7a arm64-v8a" name="TestLocaleNamePackaging">
+                            <Test name="run-everything"/>
+                        </TestCase>
+                    </TestSuite>
+                </TestSuite>
+            </TestSuite>
+        </TestSuite>
+    </TestSuite>
+</TestPackage>
diff --git a/tests/tests/icu/CtsIcuTestCases_mips.xml b/tests/tests/icu/CtsIcuTestCases_mips.xml
new file mode 100644
index 0000000..beeae32
--- /dev/null
+++ b/tests/tests/icu/CtsIcuTestCases_mips.xml
@@ -0,0 +1,563 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<TestPackage AndroidFramework="Android 1.0"
+             appNameSpace="android.icu.cts"
+             appPackageName="com.ibm.icu.dev.test"
+             name="CtsIcuTestCases"
+             runner=".IcuTestRunner"
+             version="1.0">
+
+    <!--
+    ICU tests are run against ICU as a standalone library so the package names are com.ibm.icu.*.
+    Each test class has one dummy method called "run-everything". This is because CTS will not try
+    to run a class if there is no known test method on it. The IcuTestRunner is aware of this and
+    pretends to run the method "run-everything", but actually dispatches the run to ICU's own test
+    runner. If the test is successful, a return code of 0 from ICU's test runner will be detected
+    and we report that the "run-everything" method passed. If there is any failure in the class,
+    we report that "run-everything" failed and print out the detailed method by method listing
+    from ICU about what actually failed, as the stack trace for the failure in "run-everything".
+    -->
+
+    <TestSuite name="com">
+        <TestSuite name="ibm">
+            <TestSuite name="icu">
+                <TestSuite name="dev">
+                    <TestSuite name="test">
+                        <TestSuite name="translit">
+                            <TestCase abis="mips mips64" name="PrettyPrinterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TransliteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="RegexUtilitiesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ReplaceableTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="RoundTripTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="AnyScriptTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ErrorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UnicodeMapTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64"
+                                      name="CompoundTransliteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TestUnicodeProperty">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="util">
+                            <TestCase abis="mips mips64"
+                                      name="ICUResourceBundleCollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ULocaleCollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="GenderInfoTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="BytesTrieTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="LocaleDataTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CurrencyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="RegionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ULocaleTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="StringTokenizerTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CharsTrieTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CompactArrayTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="LocaleBuilderTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TrieMapTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ICUServiceThreadTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ICUBinaryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ICUResourceBundleTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="DebugUtilitiesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64"
+                                      name="SimplePatternFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="LocaleMatcherTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UtilityTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="Trie2Test">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ICUServiceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="VersionInfoTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="LocalePriorityListTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TrieTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TextTrieMapTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="search">
+                            <TestCase abis="mips mips64" name="SearchTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="collator">
+                            <TestCase abis="mips mips64" name="LotusCollationKoreanTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationTurkishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationMiscTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationAPITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationServiceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="AlphabeticIndexTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationFinnishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationDummyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationRegressionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationChineseTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationGermanTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="G7CollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationSpanishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64"
+                                      name="CollationCreationMethodTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UCAConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationKanaTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationFrenchTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationIteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationThaiTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationFrozenMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationThreadTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationEnglishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CollationCurrencyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="format">
+                            <TestCase abis="mips mips64"
+                                      name="GlobalizationPreferencesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="RbnfLenientScannerTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="PluralRangesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="SelectFormatUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="PluralRulesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64"
+                                      name="RelativeDateTimeFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="RBNFParseTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TimeUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="CompactDecimalFormatTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="RbnfRoundTripTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="RbnfTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="SelectFormatAPITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="PluralFormatTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="BigNumberFormatTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ListFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="DateTimeGeneratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64"
+                                      name="NumberFormatSpecificationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="MeasureUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64"
+                                      name="ScientificNumberFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="PluralFormatUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="compression">
+                            <TestCase abis="mips mips64" name="ExhaustiveTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="DecompressionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="text">
+                            <TestCase abis="mips mips64" name="SpoofCheckerTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="iterator">
+                            <TestCase abis="mips mips64" name="TestUCharacterIterator">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="duration">
+                            <TestSuite name="languages">
+                                <TestCase abis="mips mips64"
+                                          name="Test_en">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_es">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_fr">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_he_IL">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_hi">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_it">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_ja">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_ko">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_zh_Hans">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_zh_Hans_SG">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_zh_Hant">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="mips mips64"
+                                          name="Test_zh_Hant_HK">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                            </TestSuite>
+                            <TestCase abis="mips mips64"
+                                      name="ResourceBasedPeriodFormatterDataServiceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ICUDurationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="PeriodBuilderFactoryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="PeriodBuilderTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="PeriodTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="DataReadWriteTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="RegressionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="rbbi">
+                            <TestCase abis="mips mips64" name="RBBITestExtended">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="SimpleBITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="BreakIteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="RBBITestMonkey">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="RBBITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="BreakIteratorRegTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="lang">
+                            <TestCase abis="mips mips64" name="TestUScript">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UPropertyAliasesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UTF16Test">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UCharacterCategoryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UnicodeSetStringSpanTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UnicodeSetTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UCharacterCaseTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UCharacterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UCharacterThreadTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UCharacterSurrogateTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TestUScriptRun">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UCharacterDirectionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="charsetdet">
+                            <TestCase abis="mips mips64" name="TestCharsetDetector">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="normalizer">
+                            <TestCase abis="mips mips64"
+                                      name="TestDeprecatedNormalizerAPI">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="NormalizationMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TestCanonicalIterator">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="BasicTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="ConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="NormalizerRegressionTests">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="UTS46Test">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64"
+                                      name="UnicodeNormalizerConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="bidi">
+                            <TestCase abis="mips mips64" name="BidiTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="BiDiConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="shaping">
+                            <TestCase abis="mips mips64" name="ArabicShapingRegTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="stringprep">
+                            <TestCase abis="mips mips64" name="TestStringPrep">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="IDNAConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TestIDNA">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TestStringPrepProfiles">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TestIDNARef">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="timezone">
+                            <TestCase abis="mips mips64" name="TimeZoneTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TimeZoneRuleTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TimeZoneRegression">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TimeZoneBoundaryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TimeZoneOffsetLocalTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="bigdec">
+                            <TestCase abis="mips mips64" name="DiagBigDecimal">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="calendar">
+                            <TestCase abis="mips mips64" name="CalendarTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="AstroTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="HolidayTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="timescale">
+                            <TestCase abis="mips mips64" name="TimeScaleMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TimeScaleAPITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TimeScaleDataTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="charset">
+                            <TestCase abis="mips mips64" name="TestSelection">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="mips mips64" name="TestCharset">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestCase abis="mips mips64" name="TestLocaleNamePackaging">
+                            <Test name="run-everything"/>
+                        </TestCase>
+                    </TestSuite>
+                </TestSuite>
+            </TestSuite>
+        </TestSuite>
+    </TestSuite>
+</TestPackage>
diff --git a/tests/tests/icu/CtsIcuTestCases_x86.xml b/tests/tests/icu/CtsIcuTestCases_x86.xml
new file mode 100644
index 0000000..31140f2
--- /dev/null
+++ b/tests/tests/icu/CtsIcuTestCases_x86.xml
@@ -0,0 +1,563 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<TestPackage AndroidFramework="Android 1.0"
+             appNameSpace="android.icu.cts"
+             appPackageName="com.ibm.icu.dev.test"
+             name="CtsIcuTestCases"
+             runner=".IcuTestRunner"
+             version="1.0">
+
+    <!--
+    ICU tests are run against ICU as a standalone library so the package names are com.ibm.icu.*.
+    Each test class has one dummy method called "run-everything". This is because CTS will not try
+    to run a class if there is no known test method on it. The IcuTestRunner is aware of this and
+    pretends to run the method "run-everything", but actually dispatches the run to ICU's own test
+    runner. If the test is successful, a return code of 0 from ICU's test runner will be detected
+    and we report that the "run-everything" method passed. If there is any failure in the class,
+    we report that "run-everything" failed and print out the detailed method by method listing
+    from ICU about what actually failed, as the stack trace for the failure in "run-everything".
+    -->
+
+    <TestSuite name="com">
+        <TestSuite name="ibm">
+            <TestSuite name="icu">
+                <TestSuite name="dev">
+                    <TestSuite name="test">
+                        <TestSuite name="translit">
+                            <TestCase abis="x86 x86_64" name="PrettyPrinterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TransliteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="RegexUtilitiesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ReplaceableTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="RoundTripTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="AnyScriptTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ErrorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UnicodeMapTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64"
+                                      name="CompoundTransliteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TestUnicodeProperty">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="util">
+                            <TestCase abis="x86 x86_64"
+                                      name="ICUResourceBundleCollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ULocaleCollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="GenderInfoTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="BytesTrieTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="LocaleDataTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CurrencyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="RegionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ULocaleTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="StringTokenizerTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CharsTrieTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CompactArrayTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="LocaleBuilderTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TrieMapTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ICUServiceThreadTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ICUBinaryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ICUResourceBundleTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="DebugUtilitiesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64"
+                                      name="SimplePatternFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="LocaleMatcherTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UtilityTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="Trie2Test">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ICUServiceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="VersionInfoTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="LocalePriorityListTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TrieTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TextTrieMapTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="search">
+                            <TestCase abis="x86 x86_64" name="SearchTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="collator">
+                            <TestCase abis="x86 x86_64" name="LotusCollationKoreanTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationTurkishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationMiscTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationAPITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationServiceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="AlphabeticIndexTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationFinnishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationDummyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationRegressionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationChineseTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationGermanTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="G7CollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationSpanishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64"
+                                      name="CollationCreationMethodTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UCAConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationKanaTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationFrenchTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationIteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationThaiTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationFrozenMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationThreadTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationEnglishTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CollationCurrencyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="format">
+                            <TestCase abis="x86 x86_64"
+                                      name="GlobalizationPreferencesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="RbnfLenientScannerTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="PluralRangesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="SelectFormatUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="PluralRulesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64"
+                                      name="RelativeDateTimeFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="RBNFParseTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TimeUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="CompactDecimalFormatTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="RbnfRoundTripTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="RbnfTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="SelectFormatAPITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="PluralFormatTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="BigNumberFormatTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ListFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="DateTimeGeneratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64"
+                                      name="NumberFormatSpecificationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="MeasureUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64"
+                                      name="ScientificNumberFormatterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="PluralFormatUnitTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="compression">
+                            <TestCase abis="x86 x86_64" name="ExhaustiveTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="DecompressionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="text">
+                            <TestCase abis="x86 x86_64" name="SpoofCheckerTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="iterator">
+                            <TestCase abis="x86 x86_64" name="TestUCharacterIterator">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="duration">
+                            <TestSuite name="languages">
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_en">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_es">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_fr">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_he_IL">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_hi">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_it">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_ja">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_ko">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_zh_Hans">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_zh_Hans_SG">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_zh_Hant">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                                <TestCase abis="x86 x86_64"
+                                          name="Test_zh_Hant_HK">
+                                    <Test name="run-everything"/>
+                                </TestCase>
+                            </TestSuite>
+                            <TestCase abis="x86 x86_64"
+                                      name="ResourceBasedPeriodFormatterDataServiceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ICUDurationTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="PeriodBuilderFactoryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="PeriodBuilderTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="PeriodTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="DataReadWriteTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="RegressionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="rbbi">
+                            <TestCase abis="x86 x86_64" name="RBBITestExtended">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="SimpleBITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="BreakIteratorTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="RBBITestMonkey">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="RBBITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="BreakIteratorRegTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="lang">
+                            <TestCase abis="x86 x86_64" name="TestUScript">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UPropertyAliasesTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UTF16Test">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UCharacterCategoryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UnicodeSetStringSpanTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UnicodeSetTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UCharacterCaseTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UCharacterTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UCharacterThreadTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UCharacterSurrogateTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TestUScriptRun">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UCharacterDirectionTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="charsetdet">
+                            <TestCase abis="x86 x86_64" name="TestCharsetDetector">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="normalizer">
+                            <TestCase abis="x86 x86_64"
+                                      name="TestDeprecatedNormalizerAPI">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="NormalizationMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TestCanonicalIterator">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="BasicTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="ConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="NormalizerRegressionTests">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="UTS46Test">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64"
+                                      name="UnicodeNormalizerConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="bidi">
+                            <TestCase abis="x86 x86_64" name="BidiTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="BiDiConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="shaping">
+                            <TestCase abis="x86 x86_64" name="ArabicShapingRegTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="stringprep">
+                            <TestCase abis="x86 x86_64" name="TestStringPrep">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="IDNAConformanceTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TestIDNA">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TestStringPrepProfiles">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TestIDNARef">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="timezone">
+                            <TestCase abis="x86 x86_64" name="TimeZoneTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TimeZoneRuleTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TimeZoneRegression">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TimeZoneBoundaryTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TimeZoneOffsetLocalTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="bigdec">
+                            <TestCase abis="x86 x86_64" name="DiagBigDecimal">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="calendar">
+                            <TestCase abis="x86 x86_64" name="CalendarTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="AstroTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="HolidayTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="timescale">
+                            <TestCase abis="x86 x86_64" name="TimeScaleMonkeyTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TimeScaleAPITest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TimeScaleDataTest">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestSuite name="charset">
+                            <TestCase abis="x86 x86_64" name="TestSelection">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                            <TestCase abis="x86 x86_64" name="TestCharset">
+                                <Test name="run-everything"/>
+                            </TestCase>
+                        </TestSuite>
+                        <TestCase abis="x86 x86_64" name="TestLocaleNamePackaging">
+                            <Test name="run-everything"/>
+                        </TestCase>
+                    </TestSuite>
+                </TestSuite>
+            </TestSuite>
+        </TestSuite>
+    </TestSuite>
+</TestPackage>
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java b/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
new file mode 100644
index 0000000..5861b94
--- /dev/null
+++ b/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2015 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.icu.cts;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.os.Debug;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A drop-in replacement for AndroidJUnitTestRunner, which understands the same arguments, and has
+ * similar functionality, but runs ICU tests instead of calling the JUnit wrapper.
+ */
+public final class IcuTestRunner extends Instrumentation {
+
+    private static final String TAG = "IcuTestRunner";
+
+    /** Bundle parameter names to be sent to the host. */
+    public static final String ARGUMENT_TEST_CLASS       = "class";
+    public static final String ARGUMENT_TEST_FILE        = "testFile";
+
+    /** Token to identify results sent by this class. */
+    public static final String REPORT_KEY_ID             = "id";
+    /** This token is use to identify the ICU test class when sending results back to the host. */
+    public static final String REPORT_KEY_NAME_CLASS     = "class";
+    /** We need to have a "method" to run. We use this token to send the placeholder method. */
+    public static final String REPORT_KEY_NAME_TEST      = "test";
+    /** Token for the current test number being run. */
+    public static final String REPORT_KEY_NUM_CURRENT    = "current";
+    /** Token for the total number of tests. Must be consistent with the host side and sent
+     * otherwise the host will assume something went wrong and run each test individually.
+     */
+    public static final String REPORT_KEY_NUMTOTAL       = "numtests";
+    /** Token representing how long (in seconds) the current test took to execute. */
+    public static final String REPORT_KEY_RUNTIME        = "runtime";
+    /** Token for sending stack traces back to the host. This is displayed in the final report, so
+     * we put the ICU detailed breakdown of tests run so it is clear which test method failed.
+     */
+    public static final String REPORT_KEY_STACK          = "stack";
+    /** Indicates to the host monitoring this test that a particular test has started. This token is
+     * required to be sent for the host to pickup that the test was run.
+     */
+    public static final int    REPORT_VALUE_RESULT_START = 1;
+    /** An identifier for tests run using this class. */
+    public static final String REPORT_VALUE_ID           = "IcuTestRunner";
+    /** The name of a non-existent method for the sake of having a method name. This is required
+     * because cts-tradefed needs to know which method on the test framework to run, but we don't
+     * have that information, so we use this placeholder instead.
+     */
+    public static final String DUMMY_METHOD_NAME         = "run-everything";
+
+    /** Wait for the debugger before starting the tests. */
+    private boolean debug;
+
+    /** Only count the number of tests, and not run them. */
+    private boolean testCountOnly;
+
+    /** Contains all the wrapped ICU tests to be run in this invocation. */
+    private Set<IcuTestUtils.IcuTestWrapper> tests;
+
+
+    @Override
+    public void onCreate(Bundle args) {
+        Log.d("IcuTestRunner", "In OnCreate");
+
+        this.debug = args.getBoolean("debug");
+        this.testCountOnly = args.getBoolean("count");
+
+        // The test can be run specifying a list of classes to run, or as cts-tradefed does it,
+        // by passing a fileName with a test to run on each line.
+        List<String> classList;
+        if (args.getString(ARGUMENT_TEST_FILE) != null) {
+            // The tests are specified in a file.
+            try {
+                classList = readTestsFromFile(args.getString(ARGUMENT_TEST_FILE));
+            } catch (IOException err) {
+                finish(Activity.RESULT_CANCELED, new Bundle());
+                return;
+            }
+        } else if (args.getString(ARGUMENT_TEST_FILE) != null) {
+            // The tests are specified in a String passed in the bundle.
+            String[] classes = args.getString(ARGUMENT_TEST_CLASS).split(",");
+            classList = new ArrayList<>(Arrays.asList(classes));
+        } else {
+            // null means the runner should run all tests.
+            classList = null;
+        }
+
+        // Use all classes if a set isn't provided
+        if (classList == null) {
+            tests = IcuTestUtils.createTestAllWrappers();
+            Log.d(TAG, "Running all tests");
+        } else {
+            tests = IcuTestUtils.createTestWrappers(classList);
+            Log.d(TAG, "Running the following tests:" + classList);
+        }
+        start();
+    }
+
+    @Override
+    public void onStart() {
+        if (debug) {
+            Debug.waitForDebugger();
+        }
+
+        if (testCountOnly) {
+            Bundle testCountResult = new Bundle();
+            testCountResult.putInt(REPORT_KEY_NUMTOTAL, this.tests.size());
+            finish(Activity.RESULT_OK, testCountResult);
+            return;
+        }
+
+        int totalSuccess = 0;
+        int totalFailures = 0;
+        List<String> failedClasses = new LinkedList<>();
+
+        for (IcuTestUtils.IcuTestWrapper testWrapper : this.tests) {
+            String className = testWrapper.getTestClassName() + '\n';
+
+            Bundle currentTestResult = sendStartTestInfo(className, totalSuccess + totalFailures);
+
+            StringBuilder result = new StringBuilder();
+            try {
+                StringWriter logs = new StringWriter();
+                Log.d("IcuTestRunner", "Executing test: " + className);
+                long startTime = System.currentTimeMillis();
+                int resultCode = testWrapper.call(new PrintWriter(logs));
+                long timeTaken = System.currentTimeMillis() - startTime;
+                currentTestResult.putFloat(REPORT_KEY_RUNTIME, timeTaken / 1000);
+                if (resultCode != 0) {
+                    totalFailures++;
+                    failedClasses.add(className);
+                    // Include the detailed logs from ICU as the stack trace.
+                    currentTestResult.putString(REPORT_KEY_STACK, logs.toString());
+                    // Also append the logs to the console output.
+                    result.append("Failure: ").append(className).append(logs.toString());
+                    currentTestResult.putString(REPORT_KEY_STREAMRESULT, result.toString());
+                    sendStatus(InstrumentationTestRunner.REPORT_VALUE_RESULT_ERROR,
+                            currentTestResult);
+                } else {
+                    totalSuccess++;
+                    result.append("Success: ").append(className).append(logs.toString());
+                    currentTestResult.putString(REPORT_KEY_STREAMRESULT, result.toString());
+                    sendStatus(InstrumentationTestRunner.REPORT_VALUE_RESULT_OK, currentTestResult);
+                }
+                result.append("Total time taken: ").append(timeTaken).append("ms\n");
+            } catch (Exception e) {
+                currentTestResult.putString(REPORT_KEY_STACK,
+                        "Test code threw exception: " + e.getMessage() + '\n');
+                result.append(e.getMessage());
+                sendStatus(InstrumentationTestRunner.REPORT_VALUE_RESULT_ERROR,
+                        currentTestResult);
+            }
+        }
+        Bundle results = new Bundle();
+        if (totalFailures == 0) {
+            results.putString(REPORT_KEY_STREAMRESULT, "All " + totalSuccess + " tests passed.");
+        } else {
+            String report = "Failures " + totalFailures + '\n';
+            for (String classname : failedClasses) {
+                report += classname + '\n';
+            }
+            results.putString(REPORT_KEY_STREAMRESULT, report);
+        }
+
+        finish(Activity.RESULT_OK, results);
+    }
+
+
+    /**
+     * Send an update to the test runner informing it we are starting a test. If this is not run
+     * then the test runner will think the test was never run, and mark it as failed.
+     * @param className The name of the class being tested. Note in this CTS-ICU interoperability
+     *                  layer, there is no method names, as we only support running whole classes.
+     * @return A bundle containing test class, method (dummy), and report name. This bundle has
+     * been sent back to the host.
+     */
+    private Bundle sendStartTestInfo(String className, int testNum) {
+        Bundle data = new Bundle();
+        data.putString(REPORT_KEY_ID, REPORT_VALUE_ID);
+        data.putInt(REPORT_KEY_NUMTOTAL, 1);
+        data.putInt(REPORT_KEY_NUM_CURRENT, testNum);
+        data.putString(REPORT_KEY_NAME_CLASS, className);
+        data.putString(REPORT_KEY_NAME_TEST, DUMMY_METHOD_NAME);  // Dummy method to work with cts.
+        sendStatus(REPORT_VALUE_RESULT_START, data);
+        return data;
+    }
+
+    /**
+     * Read tests from a specified file.
+     * @return class names of tests. If there was an error reading the file, null is returned.
+     */
+    private static List<String> readTestsFromFile(String fileName) throws IOException {
+        try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
+            List<String> tests = new ArrayList<>();
+            String line;
+            while ((line = br.readLine()) != null) {
+                tests.add(line);
+            }
+            return tests;
+        } catch (IOException err) {
+            Log.e(TAG, "There was an error reading the test class list: " + err.getMessage());
+            throw err;
+        }
+    }
+
+}
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestUtils.java b/tests/tests/icu/src/android/icu/cts/IcuTestUtils.java
new file mode 100644
index 0000000..fb9af99
--- /dev/null
+++ b/tests/tests/icu/src/android/icu/cts/IcuTestUtils.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2015 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.icu.cts;
+
+import com.ibm.icu.dev.test.TestFmwk;
+
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A thin wrapper around ICU's tests, and utilities to resolve them.
+ */
+final class IcuTestUtils {
+
+    /**
+     *  The field on TestGroup which has the list of classes in it.
+     */
+    private static final Field classesToTest;
+    static {
+        // Find the field, and complain if it is not where we expected it to be.
+        try {
+            classesToTest = TestFmwk.TestGroup.class.getDeclaredField("names");
+            classesToTest.setAccessible(true);  // It's private by default.
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException("Class structure of ICU tests have changed.", nsfe);
+        }
+    }
+
+    // Instances of this class shouldn't be made.
+    private IcuTestUtils() {}
+
+    /**
+     * Resolve the individual ICU tests from a base test class which must implement TestFmwk.
+     * A TestGroup class in ICU has a private String[] containing all the class names which
+     * are run when the TestGroup is run.
+     *
+     * @param parent the base class to start looking at.
+     */
+    public static Set<IcuTestWrapper> getBaseTests(Class<?> parent)
+            throws InstantiationException, IllegalAccessException {
+
+        Set<IcuTestWrapper> tests = new HashSet<>();
+
+        // If the parent class is an instance of TestGroup, then it will have a String[] classes
+        // field which tells us where we need to go looking for the base test classes. We can then
+        // recursively call this method which will resolve the base classes from the classes we
+        // have discovered in that field.
+        if (TestFmwk.TestGroup.class.isAssignableFrom(parent)) {
+
+            String[] children = (String[]) classesToTest.get(parent.newInstance());
+
+            for (String child : children) {
+                try {
+                    /* Get the children through a recursive call, and add to sets. */
+                    tests.addAll(getBaseTests(Class.forName(child)));
+                } catch (ClassNotFoundException cnfe) {
+                    // Try to extract the full class name by prepending the parent package.
+                    // (In case the class name was specified relative to the TestGroup).
+                    String fixed = parent.getCanonicalName().replaceAll("[a-zA-Z0-9]+$", child);
+
+                    try {
+                        tests.addAll(getBaseTests(Class.forName(fixed)));
+                    } catch (ClassNotFoundException unused) {
+                        // We make sure to add any failures to find a test, in a way that will cause
+                        // that test to fail. This is to make sure that the user is properly
+                        // informed that the test was not run. Use parent exception because that
+                        // has the actual classname and not our /guess/ to normalise the class name.
+                        tests.add(new FailTest(child, cnfe));
+                    }
+                }
+            }
+
+        } else if (TestFmwk.class.isAssignableFrom(parent)) {
+            // Otherwise, if the parent class is instead an instance of TestFmwk instead, this
+            // will be a base test. We can simply add parent to the set of classes and return.
+            tests.add(new IcuTestAdapter(parent));
+        }
+
+        return tests;
+    }
+
+    /**
+     * Resolve all the ICU tests and return a set of IcuTestWrappers which will run them.
+     * See {@link IcuTestUtils#createTestWrappers(Iterable<String>)}.
+     */
+    public static Set<IcuTestWrapper> createTestAllWrappers() {
+        return createTestWrappers(Collections.singleton("com.ibm.icu.dev.test.TestAll"));
+    }
+
+    /**
+     * Resolves a set of tests in ICU from a list of class names. These class names should reference
+     * classes under the classpath com.ibm.icu.dev.test.* and extend TestFmwk (the ICU base test
+     * class). This will return a set of individual tests, any TestGroup's found will be recursively
+     * processed to extract base classes out of them, and those tests wrapped for running.
+     * @return A set of test wrappers which can be run to determine the test outcome.
+     */
+    public static Set<IcuTestWrapper> createTestWrappers(Iterable<String> classNames) {
+        Set<IcuTestWrapper> wrappedSet = new HashSet<>();
+
+        for (String className : classNames) {
+            // Work around the limitation of CTS where a test method must be provided. We only
+            // support running classes in ICU, so discard the mock test method.
+            if (className.contains("#")) {
+                className = className.substring(0, className.indexOf("#"));
+            }
+            try {
+                wrappedSet.addAll(getBaseTests(Class.forName(className)));
+            } catch (ClassNotFoundException cnfe) {
+                /* Failure to resolve the base class */
+                wrappedSet.add(new FailTest(className, cnfe));
+            } catch (InstantiationException | IllegalAccessException e) {
+                /* An error while finding the classes */
+                wrappedSet.add(new FailTest(className,
+                        new RuntimeException("Error finding test classes: " + e)));
+            }
+        }
+        return wrappedSet;
+    }
+
+
+    /**
+     * A common interface for wrapping tests to be run with IcuTestRunner.
+     */
+    public interface IcuTestWrapper {
+        /**
+         * Returns true if there was an error fetching or resolving this test.
+         * Otherwise, the test is ready to be run and this returns false.
+         */
+        boolean isError();
+
+        /**
+         * Returns the ICU class that this test will call through to.
+         */
+        String getTestClassName();
+
+        /**
+         * Execute the test and provide the return code.
+         * 0 means that the test was successfully run.
+         */
+        int call(PrintWriter pw) throws Exception;
+    }
+
+    /**
+     * Wrapper around failure to resolve a specified ICU test class.
+     * This could be due to a class not being resolved, which was
+     * specified in the ICU test suite, a user provided class which
+     * could not be found, or an error in instantiating the class.
+     */
+    private static class FailTest implements IcuTestWrapper {
+
+        public FailTest(String attemptedClassName, Exception error) {
+            this.error = error;
+            this.className = attemptedClassName;
+        }
+
+        private String className;
+        private Exception error;
+
+        public String getTestClassName() {
+            return className;
+        }
+
+        public boolean isError() {
+            return true;
+        }
+
+        public int call(PrintWriter unused) throws Exception {
+            throw error;
+        }
+    }
+
+    /**
+     * Wrap an ICU test class and override the run method so we can handle executing the test and
+     * extracting the return code, output stream, and any exceptions.
+     */
+    private static class IcuTestAdapter implements IcuTestWrapper {
+
+        /**
+         * Fully qualified name of the test class.
+         */
+        private final String name;
+
+        /**
+         * Class object from which the test will be instantiated and run.
+         */
+        private final Class<?> icuTestClass;
+
+        public IcuTestAdapter(Class<?> testClass) {
+            if (!TestFmwk.class.isAssignableFrom(testClass)) {
+                throw new IllegalArgumentException("There was an error in the testing framework."
+                        + "A test class was found which is not an instance of TestFmwk: "
+                        + testClass);
+            }
+
+            this.name = testClass.getCanonicalName();
+            this.icuTestClass = testClass;
+        }
+
+        @Override
+        public boolean isError() {
+            return false;
+        }
+
+        @Override
+        public String getTestClassName() {
+            return this.name;
+        }
+
+        @Override
+        public int call(PrintWriter pw) {
+            try {
+                TestFmwk instance = (TestFmwk) icuTestClass.newInstance();
+                return instance.run(new String[]{}, pw);
+
+            } catch (IllegalAccessException | InstantiationException iae) {
+                throw new RuntimeException("Failed to create test class: " + icuTestClass);
+            }
+        }
+    }
+
+}
diff --git a/tests/tests/jni/Android.mk b/tests/tests/jni/Android.mk
index 1aeb8b7..b65132d 100644
--- a/tests/tests/jni/Android.mk
+++ b/tests/tests/jni/Android.mk
@@ -27,6 +27,9 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
 
 LOCAL_JNI_SHARED_LIBRARIES := libjnitest
diff --git a/tests/tests/jni/AndroidManifest.xml b/tests/tests/jni/AndroidManifest.xml
index 843b322..2724573 100644
--- a/tests/tests/jni/AndroidManifest.xml
+++ b/tests/tests/jni/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.jni">
+    package="android.jni.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -24,7 +24,7 @@
 
     <!-- This is a self-instrumenting test package. -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.jni"
+                     android:targetPackage="android.jni.cts"
                      android:label="CTS tests of calling native code via JNI">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/jni/AndroidTest.xml b/tests/tests/jni/AndroidTest.xml
new file mode 100644
index 0000000..8ec1df6
--- /dev/null
+++ b/tests/tests/jni/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS JNI test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsJniTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.jni.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/keystore/Android.mk b/tests/tests/keystore/Android.mk
index e51bc04..ba43824 100644
--- a/tests/tests/keystore/Android.mk
+++ b/tests/tests/keystore/Android.mk
@@ -18,6 +18,11 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner core-tests-support
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -26,8 +31,6 @@
 
 LOCAL_SDK_VERSION := current
 
-cts_runtime_hint := 28
-
 include $(BUILD_CTS_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/keystore/AndroidManifest.xml b/tests/tests/keystore/AndroidManifest.xml
index 106a0dc..3678f63 100644
--- a/tests/tests/keystore/AndroidManifest.xml
+++ b/tests/tests/keystore/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.keystore">
+    package="android.keystore.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.INTERNET" />
@@ -25,8 +25,8 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.keystore"
-                     android:label="CTS tests of com.android.cts.keystore">
+                     android:targetPackage="android.keystore.cts"
+                     android:label="CTS tests of android.keystore.cts">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/keystore/AndroidTest.xml b/tests/tests/keystore/AndroidTest.xml
new file mode 100644
index 0000000..844cd2a
--- /dev/null
+++ b/tests/tests/keystore/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Keystore test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsKeystoreTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.keystore.cts" />
+        <option name="runtime-hint" value="16m39s" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
index f7cc586..1efcb7f 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
@@ -27,7 +27,7 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
-import com.android.cts.keystore.R;
+import android.keystore.cts.R;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
diff --git a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
index 1a24fb2..60a48e0 100644
--- a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
@@ -21,7 +21,7 @@
 import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
 
-import com.android.cts.keystore.R;
+import android.keystore.cts.R;
 
 import java.security.AlgorithmParameters;
 import java.security.InvalidKeyException;
diff --git a/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java b/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java
index ea3940d..de60e37 100644
--- a/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java
@@ -20,7 +20,7 @@
 import android.security.keystore.KeyProtection;
 import android.test.AndroidTestCase;
 
-import com.android.cts.keystore.R;
+import android.keystore.cts.R;
 
 import java.security.KeyPair;
 import java.security.Security;
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java
index d552631..fb853c9 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java
@@ -22,7 +22,7 @@
 import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
 
-import com.android.cts.keystore.R;
+import android.keystore.cts.R;
 
 import java.io.InputStream;
 import java.security.InvalidKeyException;
diff --git a/tests/tests/keystore/src/android/keystore/cts/RSASignatureTest.java b/tests/tests/keystore/src/android/keystore/cts/RSASignatureTest.java
index e28fdff..d31f2e4 100644
--- a/tests/tests/keystore/src/android/keystore/cts/RSASignatureTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/RSASignatureTest.java
@@ -28,7 +28,7 @@
 import java.util.Collection;
 import java.util.List;
 
-import com.android.cts.keystore.R;
+import android.keystore.cts.R;
 
 import android.content.Context;
 import android.security.keystore.KeyProperties;
diff --git a/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java b/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
index 6fb3954..4fa8899 100644
--- a/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
@@ -16,7 +16,7 @@
 
 package android.keystore.cts;
 
-import com.android.cts.keystore.R;
+import android.keystore.cts.R;
 
 import java.security.InvalidKeyException;
 import java.security.KeyPair;
diff --git a/tests/tests/libcorelegacy22/Android.mk b/tests/tests/libcorelegacy22/Android.mk
index fb3c503..5b114f2 100644
--- a/tests/tests/libcorelegacy22/Android.mk
+++ b/tests/tests/libcorelegacy22/Android.mk
@@ -29,4 +29,7 @@
 
 LOCAL_SDK_VERSION := 22
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/libcorelegacy22/AndroidManifest.xml b/tests/tests/libcorelegacy22/AndroidManifest.xml
index 4ff9ec2..131613e 100644
--- a/tests/tests/libcorelegacy22/AndroidManifest.xml
+++ b/tests/tests/libcorelegacy22/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.libcorelegacy22">
+    package="android.libcorelegacy22.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.READ_LOGS" />
@@ -25,7 +25,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.libcorelegacy22"
+                     android:targetPackage="android.libcorelegacy22.cts"
                      android:label="CTS tests of android APIs last available in API 22">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/libcorelegacy22/AndroidTest.xml b/tests/tests/libcorelegacy22/AndroidTest.xml
new file mode 100644
index 0000000..cdc6611
--- /dev/null
+++ b/tests/tests/libcorelegacy22/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Legacy Libcore test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsLibcoreLegacy22TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.libcorelegacy22.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/location/Android.mk b/tests/tests/location/Android.mk
index 62d0d5d..6e71659 100644
--- a/tests/tests/location/Android.mk
+++ b/tests/tests/location/Android.mk
@@ -21,6 +21,9 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/location/AndroidManifest.xml b/tests/tests/location/AndroidManifest.xml
index 5016f49..f9985ba 100644
--- a/tests/tests/location/AndroidManifest.xml
+++ b/tests/tests/location/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.location">
+    package="android.location.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -28,7 +28,7 @@
     <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.location"
+                     android:targetPackage="android.location.cts"
                      android:label="CTS tests of android.location">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/location/AndroidTest.xml b/tests/tests/location/AndroidTest.xml
new file mode 100644
index 0000000..178e8d1
--- /dev/null
+++ b/tests/tests/location/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Location test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsLocationTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.location.cts" />
+        <option name="runtime-hint" value="1m26s" />
+    </test>
+
+</configuration>
diff --git a/tests/tests/location2/Android.mk b/tests/tests/location2/Android.mk
index 5b227b2..5e9d7da 100644
--- a/tests/tests/location2/Android.mk
+++ b/tests/tests/location2/Android.mk
@@ -21,6 +21,9 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/location2/AndroidManifest.xml b/tests/tests/location2/AndroidManifest.xml
index b2e0802..766aab4 100644
--- a/tests/tests/location2/AndroidManifest.xml
+++ b/tests/tests/location2/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.location2">
+    package="android.location2.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -27,7 +27,7 @@
     <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.location2"
+                     android:targetPackage="android.location2.cts"
                      android:label="CTS tests of android.location">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/location2/AndroidTest.xml b/tests/tests/location2/AndroidTest.xml
new file mode 100644
index 0000000..5829249
--- /dev/null
+++ b/tests/tests/location2/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Location test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsLocation2TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.location2.cts" />
+    </test>
+
+</configuration>
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index ea7256d..16989f5 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -34,12 +34,13 @@
 LOCAL_MODULE_TAGS := optional
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
 
 # include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctsmediautil ctsdeviceutil ctstestserver ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util ctstestserver ctstestrunner
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni libaudio_jni
 
@@ -51,8 +52,9 @@
 #LOCAL_SDK_VERSION := current
 LOCAL_JAVA_LIBRARIES += android.test.runner org.apache.http.legacy
 
-cts_runtime_hint := 265
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
-include $(BUILD_CTS_PACKAGE)
+include $(BUILD_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/media/AndroidManifest.xml b/tests/tests/media/AndroidManifest.xml
index cdc0e60..7645e0c 100644
--- a/tests/tests/media/AndroidManifest.xml
+++ b/tests/tests/media/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.media">
+    package="android.media.cts">
 
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
@@ -88,7 +88,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.media"
+                     android:targetPackage="android.media.cts"
                      android:label="CTS tests of android.media">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/media/AndroidTest.xml b/tests/tests/media/AndroidTest.xml
new file mode 100644
index 0000000..0465bf1
--- /dev/null
+++ b/tests/tests/media/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Media test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsMediaTestCases.apk" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="module-name" value="CtsMediaTestCases"/>
+        <option name="version-name" value="1.0"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.media.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/media/DynamicConfig.xml b/tests/tests/media/DynamicConfig.xml
new file mode 100644
index 0000000..702157d
--- /dev/null
+++ b/tests/tests/media/DynamicConfig.xml
@@ -0,0 +1,29 @@
+<!-- Copyright (C) 2015 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.
+-->
+
+<DynamicConfig>
+    <Config key="DecoderTest-VIDEO_URL">http://redirector.gvt1.com/videoplayback?id=c80658495af60617&amp;itag=18&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=46A04ED550CA83B79B60060BA80C79FDA5853D26.49582D382B4A9AFAA163DED38D2AE531D85603C0&amp;key=ik0&amp;user=android-device-test</Config>
+    <Config key="StreamingMediaPlayerTest-testHTTP_H264Base_AAC_Video1">http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=18&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=667AEEF54639926662CE62361400B8F8C1753B3F.15F46C382C68A9F121BA17BF1F56BEDEB4B06091&amp;key=ik0&amp;user=android-device-test</Config>
+    <Config key="StreamingMediaPlayerTest-testHTTP_H264Base_AAC_Video2">http://www.youtube.com/api/manifest/hls_variant/id/0168724d02bd9945/itag/5/source/youtube/playlist_type/DVR/ip/0.0.0.0/ipbits/0/expire/19000000000/sparams/ip,ipbits,expire,id,itag,source,playlist_type/signature/773AB8ACC68A96E5AA481996AD6A1BBCB70DCB87.95733B544ACC5F01A1223A837D2CF04DF85A3360/key/ik0/file/m3u8</Config>
+    <Config key="MediaCodecCapabilitiesTest-testAvcHigh31">http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=22&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=179525311196616BD8E1381759B0E5F81A9E91B5.C4A50E44059FEBCC6BBC78E3B3A4E0E0065777&amp;key=ik0</Config>
+    <Config key="StreamingMediaPlayerTest-testHTTP_MPEG4SP_AAC_Video2">http://redirector.gvt1.com/videoplayback?id=c80658495af60617&amp;itag=17&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=70E979A621001201BC18622BDBF914FA870BDA40.6E78890B80F4A33A18835F775B1FF64F0A4D0003&amp;key=ik0&amp;user=android-device-test</Config>
+    <Config key="StreamingMediaPlayerTest-testHTTP_MPEG4SP_AAC_Video1">http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=17&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=837198AAADF6F36BA6B2D324F690A7C5B7AFE3FF.7138CE5E36D718220726C1FC305497FF2D082249&amp;key=ik0&amp;user=android-device-test</Config>
+    <Config key="MediaCodecCapabilitiesTest-testAvcBaseline12">http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=160&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=9EDCA0B395B8A949C511FD5E59B9F805CFF797FD.702DE9BA7AF96785FD6930AD2DD693A0486C880E&amp;key=ik0</Config>
+    <Config key="DecoderTest-AUDIO_URL">http://redirector.gvt1.com/videoplayback?id=c80658495af60617&amp;itag=18&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=46A04ED550CA83B79B60060BA80C79FDA5853D26.49582D382B4A9AFAA163DED38D2AE531D85603C0&amp;key=ik0&amp;user=android-device-test</Config>
+    <Config key="MediaCodecCapabilitiesTest-testAvcBaseline30">http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=18&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=7DCDE3A6594D0B91A27676A3CDC3A87B149F82EA.7A83031734CB1EDCE06766B6228842F954927960&amp;key=ik0</Config>
+    <Config key="MediaCodecCapabilitiesTest-testAvcHigh40">http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=137&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=B0976085596DD42DEA3F08307F76587241CB132B.043B719C039E8B92F45391ADC0BE3665E2332930&amp;key=ik0</Config>
+    <Config key="StreamingMediaPlayerTest-testHTTP_H263_AMR_Video2">http://redirector.gvt1.com/videoplayback?id=c80658495af60617&amp;itag=13&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=508D82AB36939345BF6B8D0623CB6CABDD9C64C3.9B3336A96846DF38E5343C46AA57F6CF2956E427&amp;key=ik0&amp;user=android-device-test</Config>
+    <Config key="StreamingMediaPlayerTest-testHTTP_H263_AMR_Video1">http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=13&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=5729247E22691EBB3E804DDD523EC42DC17DD8CE.443B81C1E8E6D64E4E1555F568BA46C206507D78&amp;key=ik0&amp;user=android-device-test</Config>
+</DynamicConfig>
diff --git a/tests/tests/media/libaudiojni/sl-utils.cpp b/tests/tests/media/libaudiojni/sl-utils.cpp
index 1aa89ba..4dbb08d 100644
--- a/tests/tests/media/libaudiojni/sl-utils.cpp
+++ b/tests/tests/media/libaudiojni/sl-utils.cpp
@@ -91,8 +91,10 @@
 
 static SLObjectItf createEngine() {
     static SLEngineOption EngineOption[] = {
+        {
             (SLuint32) SL_ENGINEOPTION_THREADSAFE,
             (SLuint32) SL_BOOLEAN_TRUE
+        },
     };
     // create engine in thread-safe mode
     SLObjectItf engine;
diff --git a/tests/tests/media/res/raw/video_720x480_mp4_hevc_1638kbps_30fps_aac_stereo_128kbps_44100hz.mp4 b/tests/tests/media/res/raw/video_640x360_mp4_hevc_1638kbps_30fps_aac_stereo_128kbps_44100hz
similarity index 100%
rename from tests/tests/media/res/raw/video_720x480_mp4_hevc_1638kbps_30fps_aac_stereo_128kbps_44100hz.mp4
rename to tests/tests/media/res/raw/video_640x360_mp4_hevc_1638kbps_30fps_aac_stereo_128kbps_44100hz
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
index 34469b79..0b8b88e 100644
--- a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
+++ b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
diff --git a/tests/tests/media/src/android/media/cts/AudioEffectTest.java b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
index dce7680..b7b7f9e 100644
--- a/tests/tests/media/src/android/media/cts/AudioEffectTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.res.AssetFileDescriptor;
 import android.media.audiofx.AudioEffect;
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerStub.java b/tests/tests/media/src/android/media/cts/AudioManagerStub.java
index 290b866..947acec 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerStub.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerStub.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.app.Activity;
 import android.cts.util.CTSResult;
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index a0163e5..16b1cf3 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -35,7 +35,7 @@
 import static android.media.AudioManager.VIBRATE_TYPE_RINGER;
 import static android.provider.Settings.System.SOUND_EFFECTS_ENABLED;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.Context;
 import android.content.res.Resources;
diff --git a/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java b/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java
index de5b698..27aa866 100644
--- a/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.pm.PackageManager;
 import android.media.AudioFormat;
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index 41afab4..84c676f 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -16,9 +16,6 @@
 
 package android.media.cts;
 
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -35,9 +32,12 @@
 import android.os.Message;
 import android.util.Log;
 
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
 
 public class AudioRecordTest extends CtsAndroidTestCase {
     private final static String TAG = "AudioRecordTest";
@@ -966,38 +966,39 @@
         }
 
         // report this
-        ReportLog log = getReportLog();
-        log.printValue(reportName + ": startRecording lag", coldInputStartTime,
+        DeviceReportLog log = new DeviceReportLog();
+        log.addValue(reportName + ": startRecording lag", coldInputStartTime,
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": stop execution time", stopTime - stopRequestTime,
+        log.addValue(reportName + ": stop execution time", stopTime - stopRequestTime,
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Total record time expected", TEST_TIME_MS,
+        log.addValue(reportName + ": Total record time expected", TEST_TIME_MS,
                 ResultType.NEUTRAL, ResultUnit.MS);
-        log.printValue(reportName + ": Total record time actual", endTime - firstSampleTime,
+        log.addValue(reportName + ": Total record time actual", endTime - firstSampleTime,
                 ResultType.NEUTRAL, ResultUnit.MS);
-        log.printValue(reportName + ": Total markers expected", markerPeriods,
+        log.addValue(reportName + ": Total markers expected", markerPeriods,
                 ResultType.NEUTRAL, ResultUnit.COUNT);
-        log.printValue(reportName + ": Total markers actual", markerList.size(),
+        log.addValue(reportName + ": Total markers actual", markerList.size(),
                 ResultType.NEUTRAL, ResultUnit.COUNT);
-        log.printValue(reportName + ": Total periods expected", updatePeriods,
+        log.addValue(reportName + ": Total periods expected", updatePeriods,
                 ResultType.NEUTRAL, ResultUnit.COUNT);
-        log.printValue(reportName + ": Total periods actual", periodicList.size(),
+        log.addValue(reportName + ": Total periods actual", periodicList.size(),
                 ResultType.NEUTRAL, ResultUnit.COUNT);
-        log.printValue(reportName + ": Average Marker diff", markerStat.getAvg(),
+        log.addValue(reportName + ": Average Marker diff", markerStat.getAvg(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Maximum Marker abs diff", markerStat.getMaxAbs(),
+        log.addValue(reportName + ": Maximum Marker abs diff", markerStat.getMaxAbs(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Average Marker abs diff", markerStat.getAvgAbs(),
+        log.addValue(reportName + ": Average Marker abs diff", markerStat.getAvgAbs(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Average Periodic diff", periodicStat.getAvg(),
+        log.addValue(reportName + ": Average Periodic diff", periodicStat.getAvg(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Maximum Periodic abs diff", periodicStat.getMaxAbs(),
+        log.addValue(reportName + ": Maximum Periodic abs diff", periodicStat.getMaxAbs(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Average Periodic abs diff", periodicStat.getAvgAbs(),
+        log.addValue(reportName + ": Average Periodic abs diff", periodicStat.getAvgAbs(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printSummary(reportName + ": Unified abs diff",
+        log.setSummary(reportName + ": Unified abs diff",
                 (periodicStat.getAvgAbs() + markerStat.getAvgAbs()) / 2,
                 ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.submit(getInstrumentation());
     }
 
     private class MockOnRecordPositionUpdateListener
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index 1884493..a2d6cfb 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -28,14 +28,13 @@
 import android.media.PlaybackParams;
 import android.util.Log;
 
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
 
-import java.nio.ByteOrder;
 import java.nio.ByteBuffer;
-import java.nio.ShortBuffer;
 import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
 
 public class AudioTrackTest extends CtsAndroidTestCase {
     private String TAG = "AudioTrackTest";
@@ -2026,15 +2025,16 @@
         track.release();
         // Log the average jitter
         if (cumulativeJitterCount > 0) {
-            ReportLog log = getReportLog();
+            DeviceReportLog log = new DeviceReportLog();
             final float averageJitterInFrames = cumulativeJitter / cumulativeJitterCount;
             final float averageJitterInMs = averageJitterInFrames * 1000 / TEST_SR;
             final float maxJitterInMs = maxJitter * 1000 / TEST_SR;
             // ReportLog needs at least one Value and Summary.
-            log.printValue("Maximum Jitter", maxJitterInMs,
+            log.addValue("Maximum Jitter", maxJitterInMs,
                     ResultType.LOWER_BETTER, ResultUnit.MS);
-            log.printSummary("Average Jitter", averageJitterInMs,
+            log.setSummary("Average Jitter", averageJitterInMs,
                     ResultType.LOWER_BETTER, ResultUnit.MS);
+            log.submit(getInstrumentation());
         }
     }
 
diff --git a/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java b/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
index e059e36..37affd0 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
@@ -16,21 +16,20 @@
 
 package android.media.cts;
 
-import java.util.ArrayList;
-
 import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioTrack;
 import android.media.AudioTrack.OnPlaybackPositionUpdateListener;
-import android.media.cts.AudioHelper;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.util.Log;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import java.util.ArrayList;
 
 public class AudioTrack_ListenerTest extends CtsAndroidTestCase {
     private final static String TAG = "AudioTrack_ListenerTest";
@@ -206,22 +205,23 @@
         }
 
         // report this
-        ReportLog log = getReportLog();
-        log.printValue(reportName + ": Average Marker diff", markerStat.getAvg(),
+        DeviceReportLog log = new DeviceReportLog();
+        log.addValue(reportName + ": Average Marker diff", markerStat.getAvg(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Maximum Marker abs diff", markerStat.getMaxAbs(),
+        log.addValue(reportName + ": Maximum Marker abs diff", markerStat.getMaxAbs(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Average Marker abs diff", markerStat.getAvgAbs(),
+        log.addValue(reportName + ": Average Marker abs diff", markerStat.getAvgAbs(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Average Periodic diff", periodicStat.getAvg(),
+        log.addValue(reportName + ": Average Periodic diff", periodicStat.getAvg(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Maximum Periodic abs diff", periodicStat.getMaxAbs(),
+        log.addValue(reportName + ": Maximum Periodic abs diff", periodicStat.getMaxAbs(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printValue(reportName + ": Average Periodic abs diff", periodicStat.getAvgAbs(),
+        log.addValue(reportName + ": Average Periodic abs diff", periodicStat.getAvgAbs(),
                 ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.printSummary(reportName + ": Unified abs diff",
+        log.setSummary(reportName + ": Unified abs diff",
                 (periodicStat.getAvgAbs() + markerStat.getAvgAbs()) / 2,
                 ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.submit(getInstrumentation());
     }
 
     private class MockOnPlaybackPositionUpdateListener
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 6765051..af2145a 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -16,7 +16,8 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+import android.media.cts.R;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -65,20 +66,6 @@
     private MediaCodecTunneledPlayer mMediaCodecPlayer;
     private static final int SLEEP_TIME_MS = 1000;
     private static final long PLAY_TIME_MS = TimeUnit.MILLISECONDS.convert(1, TimeUnit.MINUTES);
-    private static final Uri AUDIO_URL = Uri.parse(
-            "http://redirector.c.youtube.com/videoplayback?id=c80658495af60617"
-                + "&itag=18&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=46A04ED550CA83B79B60060BA80C79FDA5853D26."
-                + "49582D382B4A9AFAA163DED38D2AE531D85603C0"
-                + "&key=ik0&user=android-device-test");  // H.264 Base + AAC
-    private static final Uri VIDEO_URL = Uri.parse(
-            "http://redirector.c.youtube.com/videoplayback?id=c80658495af60617"
-                + "&itag=18&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=46A04ED550CA83B79B60060BA80C79FDA5853D26."
-                + "49582D382B4A9AFAA163DED38D2AE531D85603C0"
-                + "&key=ik0&user=android-device-test");  // H.264 Base + AAC
 
     @Override
     protected void setUp() throws Exception {
@@ -1087,8 +1074,8 @@
         testDecode(R.raw.video_352x288_mp4_hevc_600kbps_30fps_aac_stereo_128kbps_44100hz, 299);
     }
 
-    public void testHEVCDecode720x480() throws Exception {
-        testDecode(R.raw.video_720x480_mp4_hevc_1638kbps_30fps_aac_stereo_128kbps_44100hz, 299);
+    public void testHEVCDecode640x360() throws Exception {
+        testDecode(R.raw.video_640x360_mp4_hevc_1638kbps_30fps_aac_stereo_128kbps_44100hz, 299);
     }
 
     public void testHEVCDecode30fps1280x720Tv() throws Exception {
@@ -1959,8 +1946,11 @@
         mMediaCodecPlayer = new MediaCodecTunneledPlayer(
                 getActivity().getSurfaceHolder(), true, am.generateAudioSessionId());
 
-        mMediaCodecPlayer.setAudioDataSource(AUDIO_URL, null);
-        mMediaCodecPlayer.setVideoDataSource(VIDEO_URL, null);
+        DynamicConfigDeviceSide config = new DynamicConfigDeviceSide("CtsMediaTestCases");
+        Uri audio_url = Uri.parse(config.getConfig("DecoderTest-AUDIO_URL"));
+        mMediaCodecPlayer.setAudioDataSource(audio_url, null);
+        Uri video_url = Uri.parse(config.getConfig("DecoderTest-VIDEO_URL"));
+        mMediaCodecPlayer.setVideoDataSource(video_url, null);
         assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
 
@@ -1998,8 +1988,11 @@
         mMediaCodecPlayer = new MediaCodecTunneledPlayer(
                 getActivity().getSurfaceHolder(), true, am.generateAudioSessionId());
 
-        mMediaCodecPlayer.setAudioDataSource(AUDIO_URL, null);
-        mMediaCodecPlayer.setVideoDataSource(VIDEO_URL, null);
+        DynamicConfigDeviceSide config = new DynamicConfigDeviceSide("CtsMediaTestCases");
+        Uri audio_url = Uri.parse(config.getConfig("DecoderTest-AUDIO_URL"));
+        mMediaCodecPlayer.setAudioDataSource(audio_url, null);
+        Uri video_url = Uri.parse(config.getConfig("DecoderTest-VIDEO_URL"));
+        mMediaCodecPlayer.setVideoDataSource(video_url, null);
         assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
 
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
index a999135..b49f07e 100644
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
@@ -58,7 +58,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -1292,7 +1292,7 @@
 
         void connect() throws Exception {
             Intent intent = new Intent();
-            intent.setClassName("com.android.cts.media",
+            intent.setClassName("android.media.cts",
                     "android.media.cts.RemoteVirtualDisplayService");
             mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
             if (!mConnectionWait.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
diff --git a/tests/tests/media/src/android/media/cts/EncoderTest.java b/tests/tests/media/src/android/media/cts/EncoderTest.java
index 4b2a168..c8cea22 100644
--- a/tests/tests/media/src/android/media/cts/EncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/EncoderTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.Context;
 import android.media.MediaCodec;
@@ -26,16 +26,21 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 public class EncoderTest extends AndroidTestCase {
     private static final String TAG = "EncoderTest";
     private static final boolean VERBOSE = false;
 
-    private static final int kNumInputBytes = 256 * 1024;
-    private static final long kTimeoutUs = 10000;
+    private static final int kNumInputBytes = 512 * 1024;
+    private static final long kTimeoutUs = 100;
 
     @Override
     public void setContext(Context context) {
@@ -121,15 +126,19 @@
     private void testEncoderWithFormats(
             String mime, List<MediaFormat> formats) {
         List<String> componentNames = getEncoderNamesForType(mime);
+        ExecutorService pool = Executors.newFixedThreadPool(3);
 
         for (String componentName : componentNames) {
-            Log.d(TAG, "testing component '" + componentName + "'");
             for (MediaFormat format : formats) {
-                Log.d(TAG, "  testing format '" + format + "'");
                 assertEquals(mime, format.getString(MediaFormat.KEY_MIME));
-                testEncoder(componentName, format);
+                pool.execute(new EncoderRun(componentName, format));
             }
         }
+        try {
+            pool.shutdown();
+            pool.awaitTermination(5, TimeUnit.MINUTES);
+        } catch (InterruptedException e) {
+        }
     }
 
     private List<String> getEncoderNamesForType(String mime) {
@@ -151,15 +160,41 @@
         return names;
     }
 
-    private int queueInputBuffer(
-            MediaCodec codec, ByteBuffer[] inputBuffers, int index) {
-        ByteBuffer buffer = inputBuffers[index];
-        buffer.clear();
+    // See bug 25843966
+    private long[] mBadSeeds = {
+            101833462733980l, // fail @ 23680 in all-random mode
+            273262699095706l, // fail @ 58880 in all-random mode
+            137295510492957l, // fail @ 35840 in zero-lead mode
+            57821391502855l,  // fail @ 32000 in zero-lead mode
+    };
 
+    private Random mRandom = new Random(1);
+
+    private int queueInputBuffer(
+            MediaCodec codec, ByteBuffer[] inputBuffers, int index,
+            boolean random, boolean zeroLead) {
+        ByteBuffer buffer = inputBuffers[index];
+        buffer.rewind();
         int size = buffer.limit();
 
-        byte[] zeroes = new byte[size];
-        buffer.put(zeroes);
+        if (random) {
+            if (zeroLead) {
+                buffer.putInt(0);
+                buffer.putInt(0);
+                buffer.putInt(0);
+                buffer.putInt(0);
+            }
+            while (true) {
+                try {
+                    buffer.putInt(mRandom.nextInt());
+                } catch (BufferOverflowException ex) {
+                    break;
+                }
+            }
+        } else {
+            byte[] zeroes = new byte[size];
+            buffer.put(zeroes);
+        }
 
         codec.queueInputBuffer(index, 0 /* offset */, size, 0 /* timeUs */, 0);
 
@@ -172,7 +207,35 @@
         codec.releaseOutputBuffer(index, false /* render */);
     }
 
+    class EncoderRun implements Runnable {
+        String mComponentName;
+        MediaFormat mFormat;
+
+        EncoderRun(String componentName, MediaFormat format) {
+            mComponentName = componentName;
+            mFormat = format;
+        }
+        @Override
+        public void run() {
+            testEncoder(mComponentName, mFormat);
+        }
+    }
+
     private void testEncoder(String componentName, MediaFormat format) {
+        Log.i(TAG, "testEncoder " + componentName + "/" + format);
+        // test with all zeroes/silence
+        testEncoder(componentName, format, false, 0, false);
+
+        // test with random data, with and without a few leading zeroes
+        for (int i = 0; i < mBadSeeds.length; i++) {
+            testEncoder(componentName, format, true, mBadSeeds[i], false);
+            testEncoder(componentName, format, true, mBadSeeds[i], true);
+        }
+    }
+
+    private void testEncoder(String componentName, MediaFormat format, boolean random,
+            long startSeed, boolean zeroLead) {
+        mRandom.setSeed(startSeed);
         MediaCodec codec;
         try {
             codec = MediaCodec.createByCodecName(componentName);
@@ -220,7 +283,7 @@
                         doneSubmittingInput = true;
                     } else {
                         int size = queueInputBuffer(
-                                codec, codecInputBuffers, index);
+                                codec, codecInputBuffers, index, random, zeroLead);
 
                         numBytesSubmitted += size;
 
diff --git a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
index 8650d20..1af825c 100644
--- a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
+++ b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
@@ -35,7 +35,7 @@
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecInfo.CodecProfileLevel;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/tests/tests/media/src/android/media/cts/FaceDetectorStub.java b/tests/tests/media/src/android/media/cts/FaceDetectorStub.java
index b1cb82d..6635fda 100644
--- a/tests/tests/media/src/android/media/cts/FaceDetectorStub.java
+++ b/tests/tests/media/src/android/media/cts/FaceDetectorStub.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.app.Activity;
 import android.media.FaceDetector.Face;
diff --git a/tests/tests/media/src/android/media/cts/FaceDetectorTest.java b/tests/tests/media/src/android/media/cts/FaceDetectorTest.java
index 4eebd52..4df0475 100644
--- a/tests/tests/media/src/android/media/cts/FaceDetectorTest.java
+++ b/tests/tests/media/src/android/media/cts/FaceDetectorTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 
 import android.content.Intent;
diff --git a/tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java b/tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java
index 32c68fb..9dc06ec2 100644
--- a/tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java
+++ b/tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 
 import android.content.Intent;
diff --git a/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java b/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java
index cc28b86..f1b2972 100644
--- a/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
diff --git a/tests/tests/media/src/android/media/cts/JetPlayerTest.java b/tests/tests/media/src/android/media/cts/JetPlayerTest.java
index 4df3555..dce792a 100644
--- a/tests/tests/media/src/android/media/cts/JetPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/JetPlayerTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 
 import android.content.res.AssetFileDescriptor;
diff --git a/tests/tests/media/src/android/media/cts/LoudnessEnhancerTest.java b/tests/tests/media/src/android/media/cts/LoudnessEnhancerTest.java
index 5b4d1aa..7c36588 100644
--- a/tests/tests/media/src/android/media/cts/LoudnessEnhancerTest.java
+++ b/tests/tests/media/src/android/media/cts/LoudnessEnhancerTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.Context;
 import android.media.audiofx.AudioEffect;
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
index 02bdd7f..3e8458b 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
@@ -33,7 +33,7 @@
     private static final long TIME_OUT_MS = 3000L;
     private static final long WAIT_TIME_FOR_NO_RESPONSE_MS = 500L;
     private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
-            "com.android.cts.media", "android.media.cts.StubMediaBrowserService");
+            "android.media.cts", "android.media.cts.StubMediaBrowserService");
     private final Object mWaitLock = new Object();
 
     private final MediaBrowser.ConnectionCallback mConnectionCallback =
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
index 7dd978f..40a86c0 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
@@ -30,7 +30,7 @@
     // The maximum time to wait for an operation.
     private static final long TIME_OUT_MS = 3000L;
     private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
-            "com.android.cts.media", "android.media.cts.StubMediaBrowserService");
+            "android.media.cts", "android.media.cts.StubMediaBrowserService");
     private static final ComponentName TEST_INVALID_BROWSER_SERVICE = new ComponentName(
             "invalid.package", "invalid.ServiceClassName");
     private final StubConnectionCallback mConnectionCallback = new StubConnectionCallback();
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index 71cbd61..7135dab 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -36,6 +36,8 @@
 import android.os.Build;
 import android.util.Log;
 
+import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.Set;
@@ -172,39 +174,28 @@
             return; // skip
         }
 
-        playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
-                + "&itag=160&source=youtube&user=android-device-test"
-                + "&sparams=ip,ipbits,expire,id,itag,source,user"
-                + "&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&signature=9EDCA0B395B8A949C511FD5E59B9F805CFF797FD."
-                + "702DE9BA7AF96785FD6930AD2DD693A0486C880E"
-                + "&key=ik0", 256, 144, PLAY_TIME_MS);
+        String url = new DynamicConfigDeviceSide("CtsMediaTestCases")
+                .getConfig("MediaCodecCapabilitiesTest-testAvcBaseline12");
+        playVideoWithRetries(url, 256, 144, PLAY_TIME_MS);
     }
 
     public void testAvcBaseline30() throws Exception {
         if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel3)) {
             return; // skip
         }
-        playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
-                + "&itag=18&source=youtube&user=android-device-test"
-                + "&sparams=ip,ipbits,expire,id,itag,source,user"
-                + "&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&signature=7DCDE3A6594D0B91A27676A3CDC3A87B149F82EA."
-                + "7A83031734CB1EDCE06766B6228842F954927960"
-                + "&key=ik0", 640, 360, PLAY_TIME_MS);
+        String url = new DynamicConfigDeviceSide("CtsMediaTestCases")
+                .getConfig("MediaCodecCapabilitiesTest-testAvcBaseline30");
+        playVideoWithRetries(url, 640, 360, PLAY_TIME_MS);
     }
 
     public void testAvcHigh31() throws Exception {
         if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileHigh, AVCLevel31)) {
             return; // skip
         }
-        playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
-                + "&itag=22&source=youtube&user=android-device-test"
-                + "&sparams=ip,ipbits,expire,id,itag,source,user"
-                + "&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&signature=179525311196616BD8E1381759B0E5F81A9E91B5."
-                + "C4A50E44059FEBCC6BBC78E3B3A4E0E0065777"
-                + "&key=ik0", 1280, 720, PLAY_TIME_MS);
+
+        String url = new DynamicConfigDeviceSide("CtsMediaTestCases")
+                .getConfig("MediaCodecCapabilitiesTest-testAvcHigh31");
+        playVideoWithRetries(url, 1280, 720, PLAY_TIME_MS);
     }
 
     public void testAvcHigh40() throws Exception {
@@ -215,13 +206,10 @@
             MediaUtils.skipTest(TAG, "fragmented mp4 not supported");
             return;
         }
-        playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
-                + "&itag=137&source=youtube&user=android-device-test"
-                + "&sparams=ip,ipbits,expire,id,itag,source,user"
-                + "&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&signature=B0976085596DD42DEA3F08307F76587241CB132B."
-                + "043B719C039E8B92F45391ADC0BE3665E2332930"
-                + "&key=ik0", 1920, 1080, PLAY_TIME_MS);
+
+        String url = new DynamicConfigDeviceSide("CtsMediaTestCases")
+                .getConfig("MediaCodecCapabilitiesTest-testAvcHigh40");
+        playVideoWithRetries(url, 1920, 1080, PLAY_TIME_MS);
     }
 
     public void testHevcMain1() throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index d3ab54f..d6709dd 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.res.AssetFileDescriptor;
 import android.cts.util.MediaUtils;
diff --git a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
index 9db54ff..9958e26 100644
--- a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
diff --git a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
index 54e6ef1..751e3d8 100644
--- a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
diff --git a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
index 0f664a5..562feba 100644
--- a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
@@ -27,7 +27,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
index 640083f..147bce4 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
@@ -46,7 +46,7 @@
  * from an HTTP server over a simulated "flaky" network.
  */
 public class MediaPlayerFlakyNetworkTest extends MediaPlayerTestBase {
-    private static final String PKG = "com.android.cts.media";
+    private static final String PKG = "android.media.cts";
 
     private static final String[] TEST_VIDEOS = {
         "raw/video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz",
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceStubActivity.java b/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceStubActivity.java
index c47995c..779a808 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceStubActivity.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceStubActivity.java
@@ -15,7 +15,7 @@
  */
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.app.Activity;
 import android.content.res.AssetFileDescriptor;
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java
index fc81cac..ae314d2 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java
@@ -24,12 +24,12 @@
 public class MediaPlayerSurfaceTest extends ActivityInstrumentationTestCase2<MediaPlayerSurfaceStubActivity> {
 
     public MediaPlayerSurfaceTest() {
-        super("com.android.cts.media", MediaPlayerSurfaceStubActivity.class);
+        super("android.media.cts", MediaPlayerSurfaceStubActivity.class);
     }
 
     public void testSetSurface() throws Exception {
         Bundle extras = new Bundle();
-        MediaPlayerSurfaceStubActivity activity = launchActivity("com.android.cts.media",
+        MediaPlayerSurfaceStubActivity activity = launchActivity("android.media.cts",
                 MediaPlayerSurfaceStubActivity.class, extras);
         activity.playVideo();
         activity.finish();
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index 861df41..bcc1e8d 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -15,13 +15,13 @@
  */
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.AssetFileDescriptor;
 import android.cts.util.MediaUtils;
-import android.hardware.Camera;
+import android.graphics.Rect;
 import android.media.AudioManager;
 import android.media.MediaCodec;
 import android.media.MediaDataSource;
@@ -50,7 +50,6 @@
 import java.io.File;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.util.List;
 import java.util.StringTokenizer;
 import java.util.UUID;
 import java.util.Vector;
@@ -81,6 +80,8 @@
 
     private File mOutFile;
 
+    private int mBoundsCount;
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -860,34 +861,15 @@
         return getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
     }
 
-    private Camera mCamera;
     private void testRecordedVideoPlaybackWithAngle(int angle) throws Exception {
-        int width = RECORDED_VIDEO_WIDTH;
-        int height = RECORDED_VIDEO_HEIGHT;
+        final int width = RECORDED_VIDEO_WIDTH;
+        final int height = RECORDED_VIDEO_HEIGHT;
         final String file = RECORDED_FILE;
         final long durationMs = RECORDED_DURATION_MS;
 
         if (!hasCamera()) {
             return;
         }
-
-        boolean isSupported = false;
-        mCamera = Camera.open(0);
-        Camera.Parameters parameters = mCamera.getParameters();
-        List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
-        for (Camera.Size size : previewSizes)
-        {
-            if (size.width == width && size.height == height) {
-                isSupported = true;
-                break;
-            }
-        }
-        mCamera.release();
-        mCamera = null;
-        if (!isSupported) {
-            width = previewSizes.get(0).width;
-            height = previewSizes.get(0).height;
-        }
         checkOrientation(angle);
         recordVideo(width, height, angle, file, durationMs);
         checkDisplayedVideoSize(width, height, angle, file);
@@ -1347,6 +1329,7 @@
         mMediaPlayer.setDisplay(getActivity().getSurfaceHolder());
         mMediaPlayer.setScreenOnWhilePlaying(true);
         mMediaPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+        mBoundsCount = 0;
         mMediaPlayer.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() {
             @Override
             public void onTimedText(MediaPlayer mp, TimedText text) {
@@ -1371,6 +1354,13 @@
                                      mSelectedTimedTextIndex, subtitleTrackIndex);
                         mOnTimedTextCalled.signal();
                     }
+                    Rect bounds = text.getBounds();
+                    if (bounds != null) {
+                        Log.d(LOG_TAG, "bounds: " + bounds);
+                        mBoundsCount++;
+                        Rect expected = new Rect(0, 0, 352, 288);
+                        assertEquals("wrong bounds", expected, bounds);
+                    }
                 }
             }
         });
@@ -1427,6 +1417,8 @@
         mOnTimedTextCalled.reset();
         assertTrue(mOnTimedTextCalled.waitForCountedSignals(2, 2500) >= 2);
         mMediaPlayer.stop();
+
+        assertEquals("Wrong bounds count", 2, mBoundsCount);
     }
 
     public void testGetTrackInfo() throws Throwable {
diff --git a/tests/tests/media/src/android/media/cts/MediaRandomTest.java b/tests/tests/media/src/android/media/cts/MediaRandomTest.java
index e928a8f..a8fc703 100644
--- a/tests/tests/media/src/android/media/cts/MediaRandomTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRandomTest.java
@@ -16,7 +16,7 @@
 package android.media.cts;
 
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.media.MediaRecorder;
 import android.media.MediaPlayer;
@@ -158,7 +158,7 @@
     }
 
     public MediaRandomTest() {
-        super("com.android.cts.media", MediaStubActivity.class);
+        super("android.media.cts", MediaStubActivity.class);
     }
 
     private void loadSource(int resid) throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index 4c90e56..2c2cd2f 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -90,7 +90,7 @@
     private ConditionVariable mMaxFileSizeCond;
 
     public MediaRecorderTest() {
-        super("com.android.cts.media", MediaStubActivity.class);
+        super("android.media.cts", MediaStubActivity.class);
         OUTPUT_PATH = new File(Environment.getExternalStorageDirectory(),
                 "record.out").getAbsolutePath();
         OUTPUT_PATH2 = new File(Environment.getExternalStorageDirectory(),
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
index ddf87b8..0272298 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 
 import android.content.ComponentName;
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerTest.java b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
index af7cfaa..ce93cb1 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.ComponentName;
 import android.content.ContentResolver;
diff --git a/tests/tests/media/src/android/media/cts/MediaStubActivity.java b/tests/tests/media/src/android/media/cts/MediaStubActivity.java
index df6d736..48dde25 100644
--- a/tests/tests/media/src/android/media/cts/MediaStubActivity.java
+++ b/tests/tests/media/src/android/media/cts/MediaStubActivity.java
@@ -15,7 +15,7 @@
  */
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/media/src/android/media/cts/MediaSyncTest.java b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
index de5a5f5..e211682 100644
--- a/tests/tests/media/src/android/media/cts/MediaSyncTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
@@ -15,7 +15,7 @@
  */
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
diff --git a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
index e7b08e9..deb561b 100644
--- a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
diff --git a/tests/tests/media/src/android/media/cts/ParamsTest.java b/tests/tests/media/src/android/media/cts/ParamsTest.java
index 5e32828..113be32 100644
--- a/tests/tests/media/src/android/media/cts/ParamsTest.java
+++ b/tests/tests/media/src/android/media/cts/ParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.media.PlaybackParams;
 import android.media.SyncParams;
diff --git a/tests/tests/media/src/android/media/cts/ResourceManagerTest.java b/tests/tests/media/src/android/media/cts/ResourceManagerTest.java
index 7305651..5f16bc5 100644
--- a/tests/tests/media/src/android/media/cts/ResourceManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/ResourceManagerTest.java
@@ -23,13 +23,13 @@
         extends ActivityInstrumentationTestCase2<ResourceManagerStubActivity> {
 
     public ResourceManagerTest() {
-        super("com.android.cts.media", ResourceManagerStubActivity.class);
+        super("android.media.cts", ResourceManagerStubActivity.class);
     }
 
     private void doTestReclaimResource(int type1, int type2) throws Exception {
         Bundle extras = new Bundle();
         ResourceManagerStubActivity activity = launchActivity(
-                "com.android.cts.media", ResourceManagerStubActivity.class, extras);
+                "android.media.cts", ResourceManagerStubActivity.class, extras);
         activity.testReclaimResource(type1, type2);
         activity.finish();
     }
diff --git a/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java b/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
index 4693036..0045577 100644
--- a/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
@@ -15,7 +15,7 @@
  */
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 
 import android.app.Activity;
@@ -34,7 +34,7 @@
 public class RingtoneManagerTest
         extends ActivityInstrumentationTestCase2<RingtonePickerActivity> {
 
-    private static final String PKG = "com.android.cts.media";
+    private static final String PKG = "android.media.cts";
     private static final String TAG = "RingtoneManagerTest";
 
     private RingtonePickerActivity mActivity;
diff --git a/tests/tests/media/src/android/media/cts/SoundPoolAacTest.java b/tests/tests/media/src/android/media/cts/SoundPoolAacTest.java
index a5eaf6b..9e37e39 100644
--- a/tests/tests/media/src/android/media/cts/SoundPoolAacTest.java
+++ b/tests/tests/media/src/android/media/cts/SoundPoolAacTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 public class SoundPoolAacTest extends SoundPoolTest {
 
diff --git a/tests/tests/media/src/android/media/cts/SoundPoolMidiTest.java b/tests/tests/media/src/android/media/cts/SoundPoolMidiTest.java
index a8c640e..d7900e1 100644
--- a/tests/tests/media/src/android/media/cts/SoundPoolMidiTest.java
+++ b/tests/tests/media/src/android/media/cts/SoundPoolMidiTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 public class SoundPoolMidiTest extends SoundPoolTest {
 
diff --git a/tests/tests/media/src/android/media/cts/SoundPoolOggTest.java b/tests/tests/media/src/android/media/cts/SoundPoolOggTest.java
index d35a93e..70330be 100644
--- a/tests/tests/media/src/android/media/cts/SoundPoolOggTest.java
+++ b/tests/tests/media/src/android/media/cts/SoundPoolOggTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 public class SoundPoolOggTest extends SoundPoolTest {
 
diff --git a/tests/tests/media/src/android/media/cts/SoundPoolTest.java b/tests/tests/media/src/android/media/cts/SoundPoolTest.java
index 23c4a7c..9022731 100644
--- a/tests/tests/media/src/android/media/cts/SoundPoolTest.java
+++ b/tests/tests/media/src/android/media/cts/SoundPoolTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 
 import android.content.Context;
diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
index ce61d76..a1f380c 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -26,6 +26,8 @@
 import android.util.Log;
 import android.webkit.cts.CtsTestServer;
 
+import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -73,49 +75,36 @@
             return; // skip
         }
 
-        playVideoTest("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
-                + "&itag=13&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=5729247E22691EBB3E804DDD523EC42DC17DD8CE"
-                + ".443B81C1E8E6D64E4E1555F568BA46C206507D78"
-                + "&key=ik0&user=android-device-test", 176, 144);
+        String url = new DynamicConfigDeviceSide("CtsMediaTestCases")
+                .getConfig("StreamingMediaPlayerTest-testHTTP_H263_AMR_Video1");
+        playVideoTest(url, 176, 144);
     }
     public void testHTTP_H263_AMR_Video2() throws Exception {
         if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_H263, MediaFormat.MIMETYPE_AUDIO_AMR_NB)) {
             return; // skip
         }
 
-        playVideoTest("http://redirector.c.youtube.com/videoplayback?id=c80658495af60617"
-                + "&itag=13&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=508D82AB36939345BF6B8D0623CB6CABDD9C64C3"
-                + ".9B3336A96846DF38E5343C46AA57F6CF2956E427"
-                + "&key=ik0&user=android-device-test", 176, 144);
+        String url = new DynamicConfigDeviceSide("CtsMediaTestCases")
+                .getConfig("StreamingMediaPlayerTest-testHTTP_H263_AMR_Video2");
+        playVideoTest(url, 176, 144);
     }
 
     public void testHTTP_MPEG4SP_AAC_Video1() throws Exception {
         if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
             return; // skip
         }
-
-        playVideoTest("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
-                + "&itag=17&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=837198AAADF6F36BA6B2D324F690A7C5B7AFE3FF"
-                + ".7138CE5E36D718220726C1FC305497FF2D082249"
-                + "&key=ik0&user=android-device-test", 176, 144);
+        String url = new DynamicConfigDeviceSide("CtsMediaTestCases")
+                .getConfig("StreamingMediaPlayerTest-testHTTP_MPEG4SP_AAC_Video1");
+        playVideoTest(url, 176, 144);
     }
     public void testHTTP_MPEG4SP_AAC_Video2() throws Exception {
         if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
             return; // skip
         }
 
-        playVideoTest("http://redirector.c.youtube.com/videoplayback?id=c80658495af60617"
-                + "&itag=17&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=70E979A621001201BC18622BDBF914FA870BDA40"
-                + ".6E78890B80F4A33A18835F775B1FF64F0A4D0003"
-                + "&key=ik0&user=android-device-test", 176, 144);
+        String url = new DynamicConfigDeviceSide("CtsMediaTestCases")
+                .getConfig("StreamingMediaPlayerTest-testHTTP_MPEG4SP_AAC_Video2");
+        playVideoTest(url, 176, 144);
     }
 
     public void testHTTP_H264Base_AAC_Video1() throws Exception {
@@ -123,24 +112,18 @@
             return; // skip
         }
 
-        playVideoTest("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
-                + "&itag=18&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=667AEEF54639926662CE62361400B8F8C1753B3F"
-                + ".15F46C382C68A9F121BA17BF1F56BEDEB4B06091"
-                + "&key=ik0&user=android-device-test", 640, 360);
+        String url = new DynamicConfigDeviceSide("CtsMediaTestCases")
+                .getConfig("StreamingMediaPlayerTest-testHTTP_H264Base_AAC_Video1");
+        playVideoTest(url, 640, 360);
     }
     public void testHTTP_H264Base_AAC_Video2() throws Exception {
         if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
             return; // skip
         }
 
-        playVideoTest("http://redirector.c.youtube.com/videoplayback?id=c80658495af60617"
-                + "&itag=18&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
-                + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=46A04ED550CA83B79B60060BA80C79FDA5853D26"
-                + ".49582D382B4A9AFAA163DED38D2AE531D85603C0"
-                + "&key=ik0&user=android-device-test", 640, 360);
+        String url = new DynamicConfigDeviceSide("CtsMediaTestCases")
+                .getConfig("StreamingMediaPlayerTest-testHTTP_H264Base_AAC_Video2");
+        playVideoTest(url, 640, 360);
     }
 
     // Streaming HLS video from YouTube
diff --git a/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java b/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
index 8797b9b..b999847 100644
--- a/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
@@ -36,7 +36,7 @@
 
 import com.android.cts.util.ResultType;
 import com.android.cts.util.ResultUnit;
-import com.android.cts.util.Stat;
+import com.android.compatibility.common.util.Stat;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
@@ -475,16 +475,16 @@
                352, 288, true /* isGoog */);
     }
 
-    public void testHEVC0720x0480Other() throws Exception {
+    public void testHEVC0640x0360Other() throws Exception {
         decode(VIDEO_HEVC,
-               R.raw.video_720x480_mp4_hevc_1638kbps_30fps_aac_stereo_128kbps_44100hz,
-               720, 480, false /* isGoog */);
+               R.raw.video_640x360_mp4_hevc_1638kbps_30fps_aac_stereo_128kbps_44100hz,
+               640, 360, false /* isGoog */);
     }
 
-    public void testHEVC0720x0480Goog() throws Exception {
+    public void testHEVC0640x0360Goog() throws Exception {
         decode(VIDEO_HEVC,
-               R.raw.video_720x480_mp4_hevc_1638kbps_30fps_aac_stereo_128kbps_44100hz,
-               720, 480, true /* isGoog */);
+               R.raw.video_640x360_mp4_hevc_1638kbps_30fps_aac_stereo_128kbps_44100hz,
+               640, 360, true /* isGoog */);
     }
 
     public void testHEVC1280x0720Other() throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/VideoEditorTest.java b/tests/tests/media/src/android/media/cts/VideoEditorTest.java
index 37a8246..c1097f8 100644
--- a/tests/tests/media/src/android/media/cts/VideoEditorTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoEditorTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.test.ActivityInstrumentationTestCase2;
 
diff --git a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
index fb1521d..79b7543 100644
--- a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.media.cts.CodecUtils;
 
@@ -57,7 +57,7 @@
     private static final long INIT_TIMEOUT_MS = 2000;
 
     private static final String SOURCE_URL =
-        "android.resource://com.android.cts.media/raw/video_480x360_mp4_h264_871kbps_30fps";
+        "android.resource://android.media.cts/raw/video_480x360_mp4_h264_871kbps_30fps";
 
     private final boolean DEBUG = false;
 
diff --git a/tests/tests/media/src/android/media/cts/VideoSurfaceView.java b/tests/tests/media/src/android/media/cts/VideoSurfaceView.java
index 229c6f6..76c3015 100644
--- a/tests/tests/media/src/android/media/cts/VideoSurfaceView.java
+++ b/tests/tests/media/src/android/media/cts/VideoSurfaceView.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import java.io.IOException;
 
diff --git a/tests/tests/media/src/android/media/cts/VirtualizerTest.java b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
index ac8eb84..0fc9f31 100644
--- a/tests/tests/media/src/android/media/cts/VirtualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
@@ -24,7 +24,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import java.util.Arrays;
 
diff --git a/tests/tests/media/src/android/media/cts/VisualizerTest.java b/tests/tests/media/src/android/media/cts/VisualizerTest.java
index 0d46ca7..141e339 100644
--- a/tests/tests/media/src/android/media/cts/VisualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/VisualizerTest.java
@@ -16,7 +16,7 @@
 
 package android.media.cts;
 
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import android.content.Context;
 import android.media.audiofx.AudioEffect;
diff --git a/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java b/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
index 133b91d..0395ec7 100644
--- a/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
+++ b/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
@@ -30,7 +30,7 @@
 import android.os.Handler;
 import android.test.AndroidTestCase;
 import android.util.Log;
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import java.io.File;
 import java.io.FileInputStream;
diff --git a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java b/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
index be7e721..5552f6c 100644
--- a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
@@ -21,7 +21,7 @@
 import android.media.MediaCodecList;
 import android.media.MediaFormat;
 import android.util.Log;
-import com.android.cts.media.R;
+import android.media.cts.R;
 
 import java.io.File;
 import java.util.ArrayList;
diff --git a/tests/tests/mediastress/Android.mk b/tests/tests/mediastress/Android.mk
index d78ddac..38d8bf6 100644
--- a/tests/tests/mediastress/Android.mk
+++ b/tests/tests/mediastress/Android.mk
@@ -20,11 +20,16 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil
 
+LOCAL_HOST_SHARED_LIBRARIES := compatibility-device-media-preconditions
+
 LOCAL_JNI_SHARED_LIBRARIES := libctsmediastress_jni
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -33,8 +38,6 @@
 
 LOCAL_SDK_VERSION := current
 
-cts_runtime_hint := 170
-
 include $(BUILD_CTS_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/mediastress/AndroidManifest.xml b/tests/tests/mediastress/AndroidManifest.xml
index 9d48c8c..e4ab36c 100644
--- a/tests/tests/mediastress/AndroidManifest.xml
+++ b/tests/tests/mediastress/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.mediastress">
+        package="android.mediastress.cts">
 
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
@@ -40,7 +40,7 @@
                   android:label="NativeMedia" />
     </application>
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.mediastress"
+            android:targetPackage="android.mediastress.cts"
             android:label="Media stress tests InstrumentationRunner" >
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/mediastress/AndroidTest.xml b/tests/tests/mediastress/AndroidTest.xml
new file mode 100644
index 0000000..43eae94
--- /dev/null
+++ b/tests/tests/mediastress/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Media Stress test cases">
+    <target_preparer class="android.mediastress.cts.preconditions.MediaPreparer" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsMediaStressTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.mediastress.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/mediastress/preconditions/Android.mk b/tests/tests/mediastress/preconditions/Android.mk
new file mode 100644
index 0000000..5838386
--- /dev/null
+++ b/tests/tests/mediastress/preconditions/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed_v2 tradefed-prebuilt
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := compatibility-host-media-preconditions
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java b/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java
new file mode 100644
index 0000000..08097f9
--- /dev/null
+++ b/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2015 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.mediastress.cts.preconditions;
+
+import com.android.compatibility.common.tradefed.targetprep.PreconditionPreparer;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.Log;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.ZipUtil;
+
+import java.awt.Dimension;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipFile;
+
+/**
+ * Ensures that the appropriate media files exist on the device
+ */
+@OptionClass(alias="media-preparer")
+public class MediaPreparer extends PreconditionPreparer {
+
+    @Option(name = "local-media-path",
+            description = "Absolute path of the media files directory, containing" +
+            "'bbb_short' and 'bbb_full' directories")
+    protected String mLocalMediaPath = null;
+
+    @Option(name = "skip-media-download",
+            description = "Whether to skip the media files precondition")
+    protected boolean mSkipMediaDownload = false;
+
+    /*
+     * The default name of local directory into which media files will be downloaded, if option
+     * "local-media-path" is not provided. This directory will live inside the temp directory.
+     */
+    protected static final String MEDIA_FOLDER_NAME = "android-cts-media";
+
+    /*
+     * The URL from which to download the compressed media files
+     * TODO: Find a way to retrieve this programmatically
+     */
+    private static final String MEDIA_URL_STRING =
+            "https://dl.google.com/dl/android/cts/android-cts-media-1.1.zip";
+
+    /*
+     * The message printed when the maximum video playback resolution cannot be found in the
+     * output of 'dumpsys'. When this is the case, media files of all resolutions must be pushed
+     * to the device.
+     */
+    private static final String MAX_PLAYBACK_RES_FAILURE_MSG =
+            "Unable to parse maximum video playback resolution, pushing all media files";
+
+    private static final String LOG_TAG = MediaPreparer.class.getSimpleName();
+
+    /* Constants identifying resolutions of the media files to be copied */
+    protected static final int RES_176_144 = 0; // 176x144 resolution
+    protected static final int RES_DEFAULT = 1; // default max video playback resolution, 480x360
+    protected static final int RES_720_480 = 2; // 720x480 resolution
+    protected static final int RES_1280_720 = 3; // 1280x720 resolution
+    protected static final int RES_1920_1080 = 4; // 1920x1080 resolution
+
+    protected static final Dimension[] resolutions = { // indices meant to align with constants above
+            new Dimension(176, 144),
+            new Dimension(480, 360),
+            new Dimension(720, 480),
+            new Dimension(1280, 720),
+            new Dimension(1920, 1080)
+    };
+
+    /*
+     * The pathnames of the device's directories that hold media files for the tests.
+     * These depend on the device's mount point, which is retrieved in the MediaPreparer's run
+     * method.
+     *
+     * These fields are exposed for unit testing
+     */
+    protected String baseDeviceShortDir;
+    protected String baseDeviceFullDir;
+
+    /*
+     * Returns a string representation of the dimension
+     * For dimension of width = 480 and height = 360, the resolution string is "480x360"
+     */
+    private static String resolutionString(Dimension resolution) {
+        return String.format("%dx%d", resolution.width, resolution.height);
+    }
+
+    /*
+     * Loops through the predefined maximum video playback resolutions from largest to smallest,
+     * And returns the greatest resolution that is strictly smaller than the width and height
+     * provided in the arguments
+     */
+    private Dimension getMaxVideoPlaybackResolution(int width, int height) {
+        for (int resIndex = resolutions.length - 1; resIndex >= RES_DEFAULT; resIndex--) {
+            Dimension resolution = resolutions[resIndex];
+            if (width >= resolution.width && height >= resolution.height) {
+                return resolution;
+            }
+        }
+        return resolutions[RES_DEFAULT];
+    }
+
+    /*
+     * Returns the maximum video playback resolution of the device, in the form of a Dimension
+     * object. This method parses dumpsys output to find resolutions listed under the
+     * 'mBaseDisplayInfo' field. The value for 'smallest app' is used as an estimate for
+     * maximum video playback resolution, and is rounded down to the nearest dimension in the
+     * resolutions array.
+     *
+     * This method is exposed for unit testing.
+     */
+    protected Dimension getMaxVideoPlaybackResolution(ITestDevice device)
+            throws DeviceNotAvailableException {
+        String dumpsysOutput =
+                device.executeShellCommand("dumpsys display | grep mBaseDisplayInfo");
+        Pattern pattern = Pattern.compile("smallest app (\\d+) x (\\d+)");
+        Matcher matcher = pattern.matcher(dumpsysOutput);
+        if(!matcher.find()) {
+            // could not find resolution in dumpsysOutput, return largest max playback resolution
+            // so that preparer copies all media files
+            CLog.e(MAX_PLAYBACK_RES_FAILURE_MSG);
+            return resolutions[RES_1920_1080];
+        }
+
+        int first;
+        int second;
+        try {
+            first = Integer.parseInt(matcher.group(1));
+            second = Integer.parseInt(matcher.group(2));
+        } catch (NumberFormatException e) {
+            CLog.e(MAX_PLAYBACK_RES_FAILURE_MSG);
+            return resolutions[RES_1920_1080];
+        }
+        // dimensions in dumpsys output seem consistently reversed
+        // here we make note of which dimension is the larger of the two
+        int height = Math.min(first, second);
+        int width = Math.max(first, second);
+        return getMaxVideoPlaybackResolution(width, height);
+    }
+
+    /*
+     * Returns true if all necessary media files exist on the device, and false otherwise.
+     *
+     * This method is exposed for unit testing.
+     */
+    protected boolean mediaFilesExistOnDevice(ITestDevice device, Dimension mvpr)
+            throws DeviceNotAvailableException{
+        int resIndex = RES_176_144;
+        while (resIndex <= RES_1920_1080) {
+            Dimension copiedResolution = resolutions[resIndex];
+            if (copiedResolution.width > mvpr.width || copiedResolution.height > mvpr.height) {
+                break; // we don't need to check for resolutions greater than or equal to this
+            }
+            String resString = resolutionString(copiedResolution);
+            String deviceShortFilePath = baseDeviceShortDir + resString;
+            String deviceFullFilePath = baseDeviceFullDir + resString;
+            if (!device.doesFileExist(deviceShortFilePath) ||
+                    !device.doesFileExist(deviceFullFilePath)) { // media files must be copied
+                return false;
+            }
+            resIndex++;
+        }
+        return true;
+    }
+
+    /* A simple helper to print messages to the tradefed console */
+    private static void printInfo(String info) {
+        LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG, info);
+    }
+
+    /*
+     * After downloading and unzipping the media files, mLocalMediaPath must be the path to the
+     * directory containing 'bbb_short' and 'bbb_full' directories, as it is defined in its
+     * description as an option.
+     * After extraction, this directory exists one level below the the directory 'mediaFolder'.
+     * If the 'mediaFolder' contains anything other than exactly one subdirectory, a
+     * TargetSetupError is thrown. Otherwise, the mLocalMediaPath variable is set to the path of
+     * this subdirectory.
+     */
+    private void updateLocalMediaPath(File mediaFolder) throws TargetSetupError {
+        String[] subDirs = mediaFolder.list();
+        if (subDirs.length != 1) {
+            throw new TargetSetupError(String.format(
+                    "Unexpected contents in directory %s", mLocalMediaPath));
+        }
+        File newMediaFolder = new File(mediaFolder, subDirs[0]);
+        mLocalMediaPath = newMediaFolder.toString();
+    }
+
+    /*
+     * Copies the media files to the host from a predefined URL
+     * Updates mLocalMediaPath to be the pathname of the directory containing bbb_short and
+     * bbb_full media directories.
+     */
+    private void downloadMediaToHost() throws TargetSetupError {
+
+        URL url;
+        try {
+            url = new URL(MEDIA_URL_STRING);
+        } catch (MalformedURLException e) {
+            throw new TargetSetupError(
+                    String.format("Trouble finding android media files at %s", MEDIA_URL_STRING));
+        }
+
+        File mediaFolder = new File(mLocalMediaPath);
+        File mediaFolderZip = new File(mediaFolder.getName() + ".zip");
+        try {
+
+            mediaFolder.mkdirs();
+            mediaFolderZip.createNewFile();
+
+            URLConnection conn = url.openConnection();
+            InputStream in = conn.getInputStream();
+            BufferedOutputStream out =
+                    new BufferedOutputStream(new FileOutputStream(mediaFolderZip));
+            byte[] buffer = new byte[1024];
+            int count;
+            printInfo("Downloading media files to host");
+            while ((count = in.read(buffer)) >= 0) {
+                out.write(buffer, 0, count);
+            }
+            out.flush();
+            out.close();
+            in.close();
+
+            printInfo("Unzipping media files");
+            ZipUtil.extractZip(new ZipFile(mediaFolderZip), mediaFolder);
+
+        } catch (IOException e) {
+            FileUtil.recursiveDelete(mediaFolder);
+            FileUtil.recursiveDelete(mediaFolderZip);
+            throw new TargetSetupError("Failed to open media files on host");
+        }
+    }
+
+    /*
+     * Pushes directories containing media files to the device for all directories that:
+     * - are not already present on the device
+     * - contain video files of a resolution less than or equal to the device's
+     *       max video playback resolution
+     *
+     * This method is exposed for unit testing.
+     */
+    protected void copyMediaFiles(ITestDevice device, Dimension mvpr)
+            throws DeviceNotAvailableException {
+
+        int resIndex = RES_176_144;
+        while (resIndex <= RES_1920_1080) {
+            Dimension copiedResolution = resolutions[resIndex];
+            String resString = resolutionString(copiedResolution);
+            if (copiedResolution.width > mvpr.width || copiedResolution.height > mvpr.height) {
+                printInfo(String.format(
+                        "Device cannot support resolutions %s and larger, media copying complete",
+                        resString));
+                return;
+            }
+            String deviceShortFilePath = baseDeviceShortDir + resString;
+            String deviceFullFilePath = baseDeviceFullDir + resString;
+            if (!device.doesFileExist(deviceShortFilePath) ||
+                    !device.doesFileExist(deviceFullFilePath)) {
+                printInfo(String.format("Copying files of resolution %s to device", resString));
+                String localShortDirName = "bbb_short/" + resString;
+                String localFullDirName = "bbb_full/" + resString;
+                File localShortDir = new File(mLocalMediaPath, localShortDirName);
+                File localFullDir = new File(mLocalMediaPath, localFullDirName);
+                // push short directory of given resolution, if not present on device
+                if(!device.doesFileExist(deviceShortFilePath)) {
+                    device.pushDir(localShortDir, deviceShortFilePath);
+                }
+                // push full directory of given resolution, if not present on device
+                if(!device.doesFileExist(deviceFullFilePath)) {
+                    device.pushDir(localFullDir, deviceFullFilePath);
+                }
+            }
+            resIndex++;
+        }
+    }
+
+    // Initialize directory strings where media files live on device
+    protected void setMountPoint(ITestDevice device) {
+        String mountPoint = device.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
+        baseDeviceShortDir = String.format("%s/test/bbb_short/", mountPoint);
+        baseDeviceFullDir = String.format("%s/test/bbb_full/", mountPoint);
+    }
+
+    @Override
+    public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+            BuildError, DeviceNotAvailableException {
+
+        if (mSkipMediaDownload) {
+            // skip this precondition
+            return;
+        }
+
+        setMountPoint(device);
+        Dimension mvpr = getMaxVideoPlaybackResolution(device);
+        if (mediaFilesExistOnDevice(device, mvpr)) {
+            // if files already on device, do nothing
+            printInfo("Media files found on the device");
+            return;
+        }
+
+        File mediaFolder;
+        if (mLocalMediaPath == null) {
+            // Option 'local-media-path' has not been defined
+            try {
+                // find system's temp directory, create folder MEDIA_FOLDER_NAME inside
+                File tmpFile = File.createTempFile(MEDIA_FOLDER_NAME, null);
+                String tmpDir = tmpFile.getParent();
+                mediaFolder = new File(tmpDir, MEDIA_FOLDER_NAME);
+                // delete temp file used for locating temp directory
+                tmpFile.delete();
+            } catch (IOException e) {
+                throw new TargetSetupError("Unable to create host temp directory for media files");
+            }
+            mLocalMediaPath = mediaFolder.getAbsolutePath();
+            if(!mediaFolder.exists()){
+                // directory has not been created by previous runs of MediaPreparer
+                // download media into mLocalMediaPath
+                downloadMediaToHost();
+            }
+            updateLocalMediaPath(mediaFolder);
+        }
+
+        printInfo(String.format("Media files located on host at: %s", mLocalMediaPath));
+        copyMediaFiles(device, mvpr);
+    }
+
+}
diff --git a/tests/tests/mediastress/preconditions/tests/Android.mk b/tests/tests/mediastress/preconditions/tests/Android.mk
new file mode 100644
index 0000000..48fdcfc
--- /dev/null
+++ b/tests/tests/mediastress/preconditions/tests/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := easymock
+
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed_v2 tradefed-prebuilt compatibility-host-media-preconditions
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := compatibility-host-media-preconditions-tests
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tests/tests/mediastress/preconditions/tests/run_tests.sh b/tests/tests/mediastress/preconditions/tests/run_tests.sh
new file mode 100755
index 0000000..1a47caf
--- /dev/null
+++ b/tests/tests/mediastress/preconditions/tests/run_tests.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright (C) 2015 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.
+
+# Helper script for running unit tests for compatibility libraries
+
+CTS_DIR=$(dirname ${0})/../../../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+    compatibility-host-util\
+    cts-tradefed_v2\
+    compatibility-host-media-preconditions\
+    compatibility-host-media-preconditions-tests"
+
+run_tests "android.mediastress.cts.preconditions.MediaPreparerTest" "${JARS}" "${@}"
diff --git a/tests/tests/mediastress/preconditions/tests/src/android/mediastress/cts/preconditions/MediaPreparerTest.java b/tests/tests/mediastress/preconditions/tests/src/android/mediastress/cts/preconditions/MediaPreparerTest.java
new file mode 100644
index 0000000..54ab025
--- /dev/null
+++ b/tests/tests/mediastress/preconditions/tests/src/android/mediastress/cts/preconditions/MediaPreparerTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 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.mediastress.cts.preconditions;
+
+import com.android.ddmlib.IDevice;
+import com.android.tradefed.build.BuildInfo;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.awt.Dimension;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+
+public class MediaPreparerTest extends TestCase {
+
+    private MediaPreparer mMediaPreparer;
+    private IBuildInfo mMockBuildInfo;
+    private ITestDevice mMockDevice;
+    private OptionSetter mOptionSetter;
+
+    private final Dimension DEFAULT_DIMENSION =
+            MediaPreparer.resolutions[MediaPreparer.RES_DEFAULT];
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mMediaPreparer = new MediaPreparer();
+        mMockDevice = EasyMock.createMock(ITestDevice.class);
+        mMockBuildInfo = new BuildInfo("0", "", "");
+        mOptionSetter = new OptionSetter(mMediaPreparer);
+    }
+
+    public void testSetMountPoint() throws Exception {
+        EasyMock.expect(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).andReturn(
+                "/sdcard").once();
+        EasyMock.replay(mMockDevice);
+        mMediaPreparer.setMountPoint(mMockDevice);
+        assertEquals(mMediaPreparer.baseDeviceShortDir, "/sdcard/test/bbb_short/");
+        assertEquals(mMediaPreparer.baseDeviceFullDir, "/sdcard/test/bbb_full/");
+    }
+
+    public void testCopyMediaFiles() throws Exception {
+        // by jumping directly into copyMediaFiles, the baseDeviceShortDir variable won't be set
+        // thus, the string "null" replaces the variable
+        EasyMock.expect(mMockDevice.doesFileExist("null176x144")).andReturn(true).anyTimes();
+        EasyMock.expect(mMockDevice.doesFileExist("null480x360")).andReturn(true).anyTimes();
+        EasyMock.replay(mMockDevice);
+        mMediaPreparer.copyMediaFiles(mMockDevice, DEFAULT_DIMENSION);
+    }
+
+    public void testMediaFilesExistOnDeviceTrue() throws Exception {
+        // by jumping directly into copyMediaFiles, the baseDeviceShortDir variable won't be set
+        // thus, the string "null" replaces the variable
+        EasyMock.expect(mMockDevice.doesFileExist("null176x144")).andReturn(true).anyTimes();
+        EasyMock.expect(mMockDevice.doesFileExist("null480x360")).andReturn(true).anyTimes();
+        EasyMock.replay(mMockDevice);
+        assertTrue(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice, DEFAULT_DIMENSION));
+    }
+
+    public void testMediaFilesExistOnDeviceFalse() throws Exception {
+        // by jumping directly into copyMediaFiles, the baseDeviceShortDir variable won't be set
+        // thus, the string "null" replaces the variable
+        EasyMock.expect(mMockDevice.doesFileExist("null176x144")).andReturn(false).anyTimes();
+        EasyMock.expect(mMockDevice.doesFileExist("null480x360")).andReturn(true).anyTimes();
+        EasyMock.replay(mMockDevice);
+        assertFalse(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice, DEFAULT_DIMENSION));
+    }
+
+    public void testGetMaxVideoPlaybackResolutionFound() throws Exception {
+        String mockDumpsysOutput = "mBaseDisplayInfo=DisplayInfo{\"Built-in Screen\", uniqueId " +
+                "\"local:0\", app 1440 x 2560, real 1440 x 2560, largest app 1440 x 2560, " +
+                "smallest app 360 x 480, mode 1, defaultMode 1, modes [{id=1, width=1440, " +
+                "height=2560, fps=60.0}], rotation 0, density 560 (494.27 x 492.606) dpi, " +
+                "layerStack 0, appVsyncOff 2500000, presDeadline 17666667, type BUILT_IN, state " +
+                "ON, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS}\n";
+        EasyMock.expect(mMockDevice.executeShellCommand(
+                "dumpsys display | grep mBaseDisplayInfo")).andReturn(mockDumpsysOutput).once();
+        EasyMock.replay(mMockDevice);
+        Dimension result = mMediaPreparer.getMaxVideoPlaybackResolution(mMockDevice);
+        assertEquals(result, DEFAULT_DIMENSION);
+    }
+
+    public void testGetMaxVideoPlaybackResolutionNotFound() throws Exception {
+        String mockDumpsysOutput = "incorrect output";
+        EasyMock.expect(mMockDevice.executeShellCommand(
+                "dumpsys display | grep mBaseDisplayInfo")).andReturn(mockDumpsysOutput).once();
+        EasyMock.replay(mMockDevice);
+        Dimension result = mMediaPreparer.getMaxVideoPlaybackResolution(mMockDevice);
+        assertEquals(result, MediaPreparer.resolutions[MediaPreparer.RES_1920_1080]);
+    }
+
+    public void testSkipMediaDownload() throws Exception {
+        mOptionSetter.setOptionValue("skip-media-download", "true");
+        EasyMock.replay();
+        mMediaPreparer.run(mMockDevice, mMockBuildInfo);
+    }
+
+}
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/MediaFrameworkTest.java b/tests/tests/mediastress/src/android/mediastress/cts/MediaFrameworkTest.java
index d39bc16..68d1e51 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/MediaFrameworkTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/MediaFrameworkTest.java
@@ -27,7 +27,7 @@
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 
-import com.android.cts.mediastress.R;
+import android.mediastress.cts.R;
 
 public class MediaFrameworkTest extends Activity implements SurfaceHolder.Callback {
     private static String TAG = "MediaFrameworkTest";
diff --git a/tests/tests/midi/Android.mk b/tests/tests/midi/Android.mk
index f202933..10ecdf1 100755
--- a/tests/tests/midi/Android.mk
+++ b/tests/tests/midi/Android.mk
@@ -22,6 +22,9 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/midi/AndroidTest.xml b/tests/tests/midi/AndroidTest.xml
new file mode 100644
index 0000000..c95ab89
--- /dev/null
+++ b/tests/tests/midi/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS MIDI test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsMidiTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.midi.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/nativemedia/Android.mk b/tests/tests/nativemedia/Android.mk
index 5053e7d..ba2da56 100644
--- a/tests/tests/nativemedia/Android.mk
+++ b/tests/tests/nativemedia/Android.mk
@@ -1 +1,15 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 include $(call all-subdir-makefiles)
diff --git a/tests/tests/nativemedia/sl/Android.mk b/tests/tests/nativemedia/sl/Android.mk
index 28dfeff..32241f3 100644
--- a/tests/tests/nativemedia/sl/Android.mk
+++ b/tests/tests/nativemedia/sl/Android.mk
@@ -1,8 +1,22 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 # Build the unit tests.
 
 LOCAL_PATH:= $(call my-dir)
 
-test_executable := NativeMediaTest_SL
+test_executable := CtsNativeMediaSlTestCases
 list_executable := $(test_executable)_list
 
 include $(CLEAR_VARS)
@@ -33,6 +47,10 @@
     libgtest
 
 LOCAL_CTS_TEST_PACKAGE := android.nativemedia.sl
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_EXECUTABLE)
 
 include $(CLEAR_VARS)
diff --git a/tests/tests/nativemedia/sl/AndroidTest.xml b/tests/tests/nativemedia/sl/AndroidTest.xml
new file mode 100644
index 0000000..c73c1b4
--- /dev/null
+++ b/tests/tests/nativemedia/sl/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Native Media Open SL ES test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsNativeMediaSlTestCases->/data/local/tmp/CtsNativeMediaSlTestCases" />
+        <option name="append-bitness" value="true" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="CtsNativeMediaSlTestCases" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/nativemedia/xa/Android.mk b/tests/tests/nativemedia/xa/Android.mk
index 52126c3..1d3608f 100644
--- a/tests/tests/nativemedia/xa/Android.mk
+++ b/tests/tests/nativemedia/xa/Android.mk
@@ -1,8 +1,22 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 # Build the unit tests.
 
 LOCAL_PATH:= $(call my-dir)
 
-test_executable := NativeMediaTest_XA
+test_executable := CtsNativeMediaXaTestCases
 list_executable := $(test_executable)_list
 
 include $(CLEAR_VARS)
@@ -32,6 +46,10 @@
   libgtest \
 
 LOCAL_CTS_TEST_PACKAGE := android.nativemedia.xa
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_EXECUTABLE)
 
 include $(CLEAR_VARS)
diff --git a/tests/tests/nativemedia/xa/AndroidTest.xml b/tests/tests/nativemedia/xa/AndroidTest.xml
new file mode 100644
index 0000000..229d8aa
--- /dev/null
+++ b/tests/tests/nativemedia/xa/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Native Media OpenMax AL test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsNativeMediaXaTestCases->/data/local/tmp/CtsNativeMediaXaTestCases" />
+        <option name="append-bitness" value="true" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="CtsNativeMediaXaTestCases" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/nativeopengl/Android.mk b/tests/tests/nativeopengl/Android.mk
deleted file mode 100644
index d2192ad..0000000
--- a/tests/tests/nativeopengl/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsNativeOpenGLTestCases
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctswrappedgtest
-
-LOCAL_JNI_SHARED_LIBRARIES := libnativeopengltests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_CTS_GTEST_PACKAGE)
-
-# Include the associated library's makefile.
-include $(LOCAL_PATH)/libnativeopengltests/Android.mk
diff --git a/tests/tests/nativeopengl/AndroidManifest.xml b/tests/tests/nativeopengl/AndroidManifest.xml
deleted file mode 100644
index 72d87ac..0000000
--- a/tests/tests/nativeopengl/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2013 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.opengl.cts">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-        <activity android:name="com.android.opengl.cts.GLTestActivity"/>
-    </application>
-
-    <!-- This is a self-instrumenting test package. -->
-    <instrumentation android:name="GLTestInstrumentation"
-                     android:targetPackage="com.android.opengl.cts"
-                     android:label="Native OpenGL tests">
-    </instrumentation>
-</manifest>
diff --git a/tests/tests/nativeopengl/CtsNativeOpenGLTestCases_list.txt b/tests/tests/nativeopengl/CtsNativeOpenGLTestCases_list.txt
deleted file mode 100644
index 8daf3b2..0000000
--- a/tests/tests/nativeopengl/CtsNativeOpenGLTestCases_list.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-EGLCleanupTest.
-  TestCorrect
-EGLCreateContextTest.
-  BadAttributeFails
-GLTest.
-  ClearColorTest
diff --git a/tests/tests/nativeopengl/libnativeopengltests/Android.mk b/tests/tests/nativeopengl/libnativeopengltests/Android.mk
deleted file mode 100644
index 9338d8b..0000000
--- a/tests/tests/nativeopengl/libnativeopengltests/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 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.
-
-#
-# This is the shared library included by the JNI test app.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libnativeopengltests
-
-# Don't include this package in any configuration by default.
-LOCAL_MODULE_TAGS := optional
-
-my_src_dir := ../standalone/jni
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/$(my_src_dir) \
-    external/gtest/include
-
-# The sources are in ../standalone/jni/
-LOCAL_SRC_FILES := $(addprefix $(my_src_dir)/, \
-        register.cpp \
-        GLTestHelper.cpp \
-        tests/GLTest_test.cpp \
-        tests/EGLCleanup_test.cpp \
-        tests/EGLCreateContext_test.cpp \
-        )
-
-LOCAL_CXX_STL := libc++
-LOCAL_SHARED_LIBRARIES := libEGL \
-                          libGLESv2 \
-                          libandroid \
-                          liblog \
-
-LOCAL_STATIC_LIBRARIES := libgtest
-
-my_src_dir :=
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/nativeopengl/src/com/android/opengl/cts/GLTestActivity.java b/tests/tests/nativeopengl/src/com/android/opengl/cts/GLTestActivity.java
deleted file mode 100644
index 1633a93..0000000
--- a/tests/tests/nativeopengl/src/com/android/opengl/cts/GLTestActivity.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 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.opengl.cts;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.Intent;
-import android.os.Bundle;
-import android.test.wrappedgtest.WrappedGTestActivity;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.Surface;
-
-public class GLTestActivity extends WrappedGTestActivity {
-
-    private SurfaceView mSurfaceView;
-    private SurfaceHolder.Callback mHolderCallback = new SurfaceHolder.Callback() {
-
-        @Override
-        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-             setSurface(holder.getSurface());
-        }
-
-        @Override
-        public void surfaceCreated(SurfaceHolder holder) {
-             setSurface(holder.getSurface());
-        }
-
-        @Override
-        public void surfaceDestroyed(SurfaceHolder holder) {
-        }
-    };
-
-    public void onCreate(Bundle data) {
-        super.onCreate(data);
-        mSurfaceView = new SurfaceView(this);
-        mSurfaceView.getHolder().addCallback(mHolderCallback);
-        setContentView(mSurfaceView);
-        System.loadLibrary("nativeopengltests");
-    }
-
-    private static native void setSurface(Surface surface);
-}
diff --git a/tests/tests/nativeopengl/src/com/android/opengl/cts/GLTestInstrumentation.java b/tests/tests/nativeopengl/src/com/android/opengl/cts/GLTestInstrumentation.java
deleted file mode 100644
index 913f0eb..0000000
--- a/tests/tests/nativeopengl/src/com/android/opengl/cts/GLTestInstrumentation.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 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.opengl.cts;
-
-import android.test.wrappedgtest.WrappedGTestInstrumentation;
-
-/**
- * adb shell am instrument -w com.android.opengl.cts/.GLTestInstrumentation
- */
-public class GLTestInstrumentation extends WrappedGTestInstrumentation {
-    public GLTestInstrumentation() {
-        mActivityClass = GLTestActivity.class;
-    }
-}
diff --git a/tests/tests/nativeopengl/standalone/.gitignore b/tests/tests/nativeopengl/standalone/.gitignore
deleted file mode 100644
index 1d1cdd2..0000000
--- a/tests/tests/nativeopengl/standalone/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-bin/
-build.xml
-gen/
-libs/
-local.properties
-obj/
-proguard-project.txt
-project.properties
diff --git a/tests/tests/nativeopengl/standalone/AndroidManifest.xml b/tests/tests/nativeopengl/standalone/AndroidManifest.xml
deleted file mode 100644
index 9092f69..0000000
--- a/tests/tests/nativeopengl/standalone/AndroidManifest.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2013 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.gltest"
-    android:versionCode="1"
-    android:versionName="1.0"
-    android:debuggable="true" >
-
-    <uses-sdk
-        android:minSdkVersion="8"
-        android:targetSdkVersion="15" />
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
-    <application android:label="NativeGLTest">
-        <activity android:name=".GLTestActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-
-</manifest>
diff --git a/tests/tests/nativeopengl/standalone/jni/Android.mk b/tests/tests/nativeopengl/standalone/jni/Android.mk
deleted file mode 100644
index 53d9bbf..0000000
--- a/tests/tests/nativeopengl/standalone/jni/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright 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.
-#
-
-MY_LOCAL_PATH := $(call my-dir)
-MY_GTEST_PATH := $(MY_LOCAL_PATH)/../../../../../../external/gtest
-
-# gtest
-
-LOCAL_PATH := $(MY_GTEST_PATH)
-
-include $(CLEAR_VARS)
-
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_MODULE := libgtest
-LOCAL_C_INCLUDES := $(MY_GTEST_PATH)/include
-LOCAL_SRC_FILES := src/gtest-all.cc
-
-include $(BUILD_STATIC_LIBRARY)
-
-# nativetests
-
-LOCAL_PATH := $(MY_LOCAL_PATH)
-
-include $(CLEAR_VARS)
-
-LIB_PATH := $(LOCAL_PATH)/../libs/$(TARGET_ARCH_ABI)/
-LOCAL_C_INCLUDES := $(MY_GTEST_PATH)/include
-LOCAL_LDLIBS    := -L$(LIB_PATH) -landroid -lEGL -lGLESv2 -llog
-LOCAL_STATIC_LIBRARIES := libgtest
-LOCAL_MODULE    := nativeopengltests
-LOCAL_SRC_FILES := GLTestHelper.cpp \
-                   register.cpp \
-                   tests/GLTest_test.cpp \
-                   tests/EGLCleanup_test.cpp \
-                   tests/EGLCreateContext_test.cpp
-
-LOCAL_SHARED_LIBRARIES := libgtest
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/nativeopengl/standalone/jni/Application.mk b/tests/tests/nativeopengl/standalone/jni/Application.mk
deleted file mode 100644
index 76d05a7..0000000
--- a/tests/tests/nativeopengl/standalone/jni/Application.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 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.
-#
-
-APP_STL := stlport_shared
diff --git a/tests/tests/nativeopengl/standalone/jni/GLTestHelper.cpp b/tests/tests/nativeopengl/standalone/jni/GLTestHelper.cpp
deleted file mode 100644
index d1f29d5..0000000
--- a/tests/tests/nativeopengl/standalone/jni/GLTestHelper.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#define LOG_TAG "GLTest"
-#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
-#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
-
-#include <android/log.h>
-#include <android/native_window.h>
-#include <GLTestHelper.h>
-
-// this listener is used to forward the subset of
-// gtest output needed to generate CTS results
-class CTSGTestListener : public EmptyTestEventListener {
-public:
-    CTSGTestListener(JNIEnv *env, jobject activity)
-        : mActivity(activity), mEnv(env) {
-
-        jclass clazz = env->FindClass(
-              "android/test/wrappedgtest/WrappedGTestActivity");
-        mSendStatusID = env->GetMethodID(clazz, "sendStatus",
-              "(Ljava/lang/String;)V");
-        mMessageBuffer = new char[2048];
-    }
-
-    ~CTSGTestListener() {
-        delete[] mMessageBuffer;
-    }
-
-private:
-    jobject   mActivity;
-    JNIEnv *  mEnv;
-    jmethodID mSendStatusID;
-    char *    mMessageBuffer;
-
-    virtual void OnTestIterationStart(const UnitTest& unit_test,
-            int iteration) {
-        snprintf(mMessageBuffer, sizeof(char) * 2048,
-                "[==========] Running %i tests from %i test cases.",
-                unit_test.test_to_run_count(),
-                unit_test.test_case_to_run_count());
-
-        mEnv->CallVoidMethod(mActivity, mSendStatusID,
-                mEnv->NewStringUTF(mMessageBuffer));
-    }
-
-    virtual void OnTestStart(const TestInfo& test_info) {
-        snprintf(mMessageBuffer, sizeof(char) * 2048, "[ RUN      ] %s.%s",
-                test_info.test_case_name(), test_info.name());
-
-        mEnv->CallVoidMethod(mActivity, mSendStatusID,
-                mEnv->NewStringUTF(mMessageBuffer));
-    }
-
-    virtual void OnTestPartResult(const TestPartResult& result) {
-        if (result.type() == TestPartResult::kSuccess) {
-            return;
-        }
-
-        snprintf(mMessageBuffer, sizeof(char) * 2048, "%s:%i: Failure\n%s",
-                result.file_name(), result.line_number(), result.message());
-
-        mEnv->CallVoidMethod(mActivity, mSendStatusID,
-                mEnv->NewStringUTF(mMessageBuffer));
-    }
-
-    virtual void OnTestEnd(const TestInfo& test_info) {
-        const char * result = test_info.result()->Passed() ?
-                "[       OK ] " : "[  FAILED  ] ";
-
-        snprintf(mMessageBuffer, sizeof(char) * 2048, "%s%s.%s (%lli ms)",
-                result, test_info.test_case_name(), test_info.name(),
-                test_info.result()->elapsed_time());
-
-        mEnv->CallVoidMethod(mActivity, mSendStatusID,
-                mEnv->NewStringUTF(mMessageBuffer));
-    }
-
-    virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) {
-        snprintf(mMessageBuffer, sizeof(char) * 2048,
-                "[==========] %i tests from %i test cases ran. (%lli ms total)",
-                unit_test.test_to_run_count(),
-                unit_test.test_case_to_run_count(), unit_test.elapsed_time());
-
-        mEnv->CallVoidMethod(mActivity, mSendStatusID,
-                mEnv->NewStringUTF(mMessageBuffer));
-    }
-};
-
-// this listener is similar to the default gtest listener
-// but it outputs the results to the log instead of stdout
-class LogGTestListener : public EmptyTestEventListener {
-
-private:
-    virtual void OnTestIterationStart(const UnitTest& unit_test,
-            int iteration) {
-        LOGI("[==========] Running %i tests from %i test cases.\n",
-                unit_test.test_to_run_count(),
-                unit_test.test_case_to_run_count());
-    }
-
-    virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) {
-        LOGI("[==========] Global test environment set-up.\n");
-    }
-
-    virtual void OnTestCaseStart(const TestCase& test_case) {
-        LOGI("[----------] %i tests from %s\n",
-                test_case.test_to_run_count(),
-                test_case.name());
-
-    }
-
-    virtual void OnTestStart(const TestInfo& test_info) {
-        LOGI("[ RUN      ] %s.%s\n", test_info.test_case_name(),
-                test_info.name());
-
-    }
-
-    virtual void OnTestPartResult(const TestPartResult& result) {
-        if (result.type() == TestPartResult::kSuccess) {
-            return;
-        }
-
-        LOGI("%s:%i: Failure\n%s\n", result.file_name(), result.line_number(),
-                result.message());
-    }
-
-    virtual void OnTestEnd(const TestInfo& test_info) {
-        const char * result = test_info.result()->Passed() ?
-                "[       OK ] " : "[  FAILED  ] ";
-
-        LOGI("%s%s.%s (%lli ms)\n", result, test_info.test_case_name(),
-                test_info.name(), test_info.result()->elapsed_time());
-    }
-
-
-    virtual void OnTestCaseEnd(const TestCase& test_case) {
-        LOGI("[----------] %i tests from %s (%lli ms total)\n",
-                test_case.test_to_run_count(), test_case.name(),
-                test_case.elapsed_time());
-
-    }
-
-    virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) {
-        LOGI("[==========] Global test environment tear-down.\n");
-    }
-
-    void PrintFailedTests(const UnitTest& unit_test) {
-        const int failed_test_count = unit_test.failed_test_count();
-        if (failed_test_count == 0) {
-            return;
-        }
-
-        for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
-            const TestCase& test_case = *unit_test.GetTestCase(i);
-
-            if (!test_case.should_run() || test_case.failed_test_count() == 0) {
-                continue;
-            }
-
-            for (int j = 0; j < test_case.total_test_count(); ++j) {
-                const TestInfo& test_info = *test_case.GetTestInfo(j);
-                if (!test_info.should_run() || test_info.result()->Passed()) {
-                    continue;
-                }
-                LOGI("[  FAILED  ] %s.%s\n", test_case.name(),
-                        test_info.name());
-            }
-        }
-    }
-    virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) {
-        LOGI("[==========] %i tests from %i test cases ran. (%lli ms total)\n",
-                unit_test.test_to_run_count(),
-                unit_test.test_case_to_run_count(), unit_test.elapsed_time());
-
-        LOGI("[  PASSED  ] %i tests\n", unit_test.successful_test_count());
-
-        if(unit_test.Passed()) {
-            return;
-        }
-
-        LOGI("[  FAILED  ] %i tests, listed below:\n",
-                unit_test.failed_test_count());
-
-        PrintFailedTests(unit_test);
-
-        LOGI("\n%2d FAILED TESTS\n", unit_test.failed_test_count());
-    }
-};
-
-ANativeWindow* GLTestHelper::mWindow;
-
-ANativeWindow* GLTestHelper::getWindow() {
-    return mWindow;
-}
-
-void GLTestHelper::setWindow(JNIEnv *env, jobject obj, jobject surface) {
-    mWindow = ANativeWindow_fromSurface(env, surface);
-}
-
-int GLTestHelper::runGTests(TestEventListener * listener, char * filter) {
-
-    if (filter) {
-        ::testing::GTEST_FLAG(filter) = filter;
-    }
-
-    int argc = 0;
-    InitGoogleTest(&argc, (char**)NULL);
-
-    TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
-    delete listeners.Release(listeners.default_result_printer());
-
-    listeners.Append(listener);
-    int result = RUN_ALL_TESTS();
-    return result;
-}
-
-int GLTestHelper::runTests(JNIEnv *env, jobject obj, jstring filter) {
-    LogGTestListener * listener = new LogGTestListener();
-
-    char * filter_cstr = NULL;
-
-    // set filter if there is one
-    if (filter) {
-       filter_cstr = new char[512];
-       const char * ptr = env->GetStringUTFChars(filter, NULL);
-       snprintf(filter_cstr, sizeof(char) * 512, "%s", ptr);
-       env->ReleaseStringUTFChars(filter, ptr);
-    }
-
-    int result = runGTests(listener, filter_cstr);
-
-    if (filter_cstr) {
-        delete[] filter_cstr;
-    }
-
-    delete listener;
-    return result;
-}
-
-int GLTestHelper::runTestsCTS(JNIEnv *env, jobject obj, jobject activity) {
-    CTSGTestListener * listener = new CTSGTestListener(env, activity);
-    int result = runGTests(listener, NULL);
-    delete listener;
-    return result;
-}
-
-int GLTestHelper::registerNative(JNIEnv * env) {
-
-    jclass clazz = env->FindClass("com/android/opengl/cts/GLTestActivity");
-
-    jthrowable exception = env->ExceptionOccurred();
-    // CTS class not found, assume stand-alone application
-    if (exception) {
-        env->ExceptionClear();
-
-        if (!env->IsInstanceOf(env->ExceptionOccurred(),
-                    env->FindClass("java/lang/NoClassDefFoundError"))) {
-            env->Throw(exception);
-        }
-
-        //
-        JNINativeMethod standaloneMethods[] = {
-            // name, signature, function
-            { "setSurface", "(Landroid/view/Surface;)V", (void*)(GLTestHelper::setWindow) },
-            { "runTests", "(Ljava/lang/String;)V", (void*)(GLTestHelper::runTests) },
-        };
-
-        return env->RegisterNatives(
-                env->FindClass("com/android/gltest/GLTestActivity"),
-                standaloneMethods,
-                sizeof(standaloneMethods) / sizeof(JNINativeMethod));
-    }
-
-    // GLTestActivity methods
-    JNINativeMethod glTestActMethods[] = {
-        // name, signature, function
-        { "setSurface", "(Landroid/view/Surface;)V", (void*)(GLTestHelper::setWindow) },
-    };
-
-    int result = env->RegisterNatives(clazz, glTestActMethods,
-                         sizeof(glTestActMethods) / sizeof(JNINativeMethod));
-
-    if (result) {
-        return result;
-    }
-
-    // WrappedGTestActivity methods
-    JNINativeMethod wrappedGTestActMethods[] = {
-        // name, signature, function
-        { "runTests", "(Landroid/test/wrappedgtest/WrappedGTestActivity;)I",
-            (void*)(GLTestHelper::runTestsCTS) },
-    };
-
-    return env->RegisterNatives(
-            env->FindClass("android/test/wrappedgtest/WrappedGTestActivity"),
-            wrappedGTestActMethods,
-            sizeof(wrappedGTestActMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/nativeopengl/standalone/jni/GLTestHelper.h b/tests/tests/nativeopengl/standalone/jni/GLTestHelper.h
deleted file mode 100644
index d09d2f1..0000000
--- a/tests/tests/nativeopengl/standalone/jni/GLTestHelper.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#ifndef ANDROID_GL_TEST_HELPER_H
-#define ANDROID_GL_TEST_HELPER_H
-
-#include <android/native_window_jni.h>
-#include <gtest/gtest.h>
-
-using namespace testing;
-
-class GLTestHelper
-{
-private:
-    static ANativeWindow* mWindow;
-    static int runGTests(TestEventListener* listener, char * filter);
-    static int runTests(JNIEnv* env, jobject obj, jstring filter);
-    static int runTestsCTS(JNIEnv* env, jobject obj, jobject activity);
-public:
-    static ANativeWindow* getWindow();
-    static void setWindow(JNIEnv* env, jobject obj, jobject surface);
-    static int registerNative(JNIEnv* env);
-};
-
-
-
-#endif // ANDROID_GL_TEST_HELPER_H
diff --git a/tests/tests/nativeopengl/standalone/jni/register.cpp b/tests/tests/nativeopengl/standalone/jni/register.cpp
deleted file mode 100644
index 8dd14ed..0000000
--- a/tests/tests/nativeopengl/standalone/jni/register.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#include <jni.h>
-#include <GLTestHelper.h>
-
-/*
- * This function is called automatically by the system when this
- * library is loaded. We use it to register all our native functions,
- * which is the recommended practice for Android.
- */
-jint JNI_OnLoad(JavaVM *vm, void *reserved) {
-    JNIEnv *env = NULL;
-
-    if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
-        return JNI_ERR;
-    }
-
-    if (GLTestHelper::registerNative(env)) {
-        return JNI_ERR;
-    }
-
-    return JNI_VERSION_1_4;
-}
diff --git a/tests/tests/nativeopengl/standalone/jni/tests/EGLCleanup_test.cpp b/tests/tests/nativeopengl/standalone/jni/tests/EGLCleanup_test.cpp
deleted file mode 100644
index 2daa2fe..0000000
--- a/tests/tests/nativeopengl/standalone/jni/tests/EGLCleanup_test.cpp
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#define LOG_TAG "EGLCleanup"
-#include <android/log.h>
-#include <jni.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#include <gtest/gtest.h>
-
-#include <GLTestHelper.h>
-
-#include <pthread.h>
-
-#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
-#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
-#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
-#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
-
-namespace android {
-
-/**
- * Tests EGL cleanup edge cases.
- */
-class EGLCleanupTest : public ::testing::Test {
-protected:
-    EGLCleanupTest() {}
-
-    virtual void SetUp() {
-        // Termination of a terminated display is defined to be a no-op.
-        // Android uses a refcounted implementation, so terminate it a few
-        // times to make sure it's really dead.  Without this, we might not
-        // get all the way into the driver eglTerminate implementation
-        // when we call eglTerminate.
-        EGLDisplay disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        if (disp != EGL_NO_DISPLAY) {
-            ALOGD("speculative terminate");
-            eglTerminate(disp);
-            eglTerminate(disp);
-            eglTerminate(disp);
-        }
-    }
-    virtual void TearDown() {}
-};
-
-/**
- * Perform an operation and then start a new thread.
- *
- * The trick here is that some code may be helpfully releasing storage in
- * pthread_key destructors.  Those run after the thread returns out of the
- * initial function, but before the thread fully exits.  We want them to
- * run concurrently with the next thread's initialization so we can confirm
- * that the specified behavior of eglTerminate vs. eglInitialize holds.
- */
-class ChainedThread {
-public:
-    enum TestType {
-        TEST_CORRECT,
-        TEST_NO_RELEASE_CURRENT
-    };
-
-    ChainedThread(TestType testType) : mEglDisplay(EGL_NO_DISPLAY),
-            mEglSurface(EGL_NO_SURFACE), mEglContext(EGL_NO_CONTEXT),
-            mTestType(testType), mIteration(0), mResult(true) {
-        pthread_mutex_init(&mLock, NULL);
-        pthread_cond_init(&mCond, NULL);
-    }
-    ~ChainedThread() {
-        // could get fancy and clean up the mutex
-    }
-
-    /* start here */
-    bool start() {
-        lock();
-        bool result = startThread_l();
-        unlock();
-        return result;
-    }
-
-    /* waits until test is done; when finished, call getResult() */
-    bool waitForEnd() {
-        lock();
-        int err = pthread_cond_wait(&mCond, &mLock);
-        if (err != 0) {
-            ALOGW("pthread_cond_wait failed: %d", err);
-        }
-        unlock();
-        return err == 0;
-    }
-
-    /* returns the result; true means success */
-    bool getResult() {
-        return mResult;
-    }
-
-private:
-    enum { MAX_ITERATIONS = 450 };
-
-    EGLDisplay mEglDisplay;
-    EGLSurface mEglSurface;
-    EGLContext mEglContext;
-
-    TestType mTestType;
-    int mIteration;
-    bool mResult;
-    pthread_mutex_t mLock;
-    pthread_cond_t mCond;
-
-    // Assertions set a flag in Java and return from the current method (which
-    // must be declared to return void).  They do not throw a C++ exception.
-    //
-    // Because we're running in a separate thread, which is not attached to
-    // the VM, the assert macros don't help us much.  We could attach to the
-    // VM (by linking to libdvm.so and calling a global function), but the
-    // assertions won't cause the test to stop, which makes them less valuable.
-    //
-    // So instead we just return a boolean out of functions that can fail.
-
-    /* call this to start the test */
-    bool startThread_l() {
-        pthread_attr_t attr;
-        pthread_attr_init(&attr);
-        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
-        pthread_t newThread;
-        int err = pthread_create(&newThread, &attr, ChainedThread::func,
-                (void*) this);
-        return (err == 0);
-    }
-
-    /* thread entry point */
-    static void* func(void* arg) {
-        ChainedThread* obj = static_cast<ChainedThread*>(arg);
-        obj->doWork();
-        return NULL;
-    }
-
-    bool lock() {
-        int err = pthread_mutex_lock(&mLock);
-        if (err != 0) {
-            ALOGW("pthread_mutex_lock failed: %d", err);
-        }
-        return err == 0;
-    }
-
-    bool unlock() {
-        int err = pthread_mutex_unlock(&mLock);
-        if (err != 0) {
-            ALOGW("pthread_mutex_unlock failed: %d", err);
-        }
-        return err == 0;
-    }
-
-    /* main worker */
-    void doWork() {
-        lock();
-
-        if ((mIteration % 25) == 0) {
-            ALOGD("iteration %d\n", mIteration);
-        }
-
-        mIteration++;
-        bool result = runTest_l();
-        if (!result) {
-            ALOGW("failed at iteration %d, stopping test", mIteration);
-            mResult = false;
-            mIteration = MAX_ITERATIONS;
-        }
-
-        if (mIteration < MAX_ITERATIONS) {
-            // still going, try to start the next one
-            if (!startThread_l()) {
-                ALOGW("Unable to start thread at iter=%d", mIteration);
-                mResult = false;
-                mIteration = MAX_ITERATIONS;
-            }
-        }
-
-        if (mIteration >= MAX_ITERATIONS) {
-            ALOGD("Test ending, signaling main thread");
-            pthread_cond_signal(&mCond);
-        }
-
-        unlock();
-    }
-
-    /* setup, use, release EGL */
-    bool runTest_l() {
-        if (!eglSetup()) {
-            return false;
-        }
-        if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
-                mEglContext))
-        {
-            ALOGW("eglMakeCurrent failed: 0x%x", eglGetError());
-            return false;
-        }
-        if (!eglRelease_l()) {
-            return false;
-        }
-
-        return true;
-    }
-
-    /*
-     * Sets up EGL.  Creates a 1280x720 pbuffer, which is large enough to
-     * cause a rapid and highly visible memory leak if we fail to discard it.
-     */
-    bool eglSetup() {
-        static const EGLint kConfigAttribs[] = {
-                EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
-                EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-                EGL_RED_SIZE, 8,
-                EGL_GREEN_SIZE, 8,
-                EGL_BLUE_SIZE, 8,
-                EGL_NONE
-        };
-        static const EGLint kContextAttribs[] = {
-                EGL_CONTEXT_CLIENT_VERSION, 2,
-                EGL_NONE
-        };
-        static const EGLint kPbufferAttribs[] = {
-                EGL_WIDTH, 1280,
-                EGL_HEIGHT, 720,
-                EGL_NONE
-        };
-
-        //usleep(25000);
-
-        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        if (mEglDisplay == EGL_NO_DISPLAY) {
-            ALOGW("eglGetDisplay failed: 0x%x", eglGetError());
-            return false;
-        }
-
-        EGLint majorVersion, minorVersion;
-        if (!eglInitialize(mEglDisplay, &majorVersion, &minorVersion)) {
-            ALOGW("eglInitialize failed: 0x%x", eglGetError());
-            return false;
-        }
-
-        EGLConfig eglConfig;
-        EGLint numConfigs = 0;
-        if (!eglChooseConfig(mEglDisplay, kConfigAttribs, &eglConfig,
-                1, &numConfigs)) {
-            ALOGW("eglChooseConfig failed: 0x%x", eglGetError());
-            return false;
-        }
-
-        mEglSurface = eglCreatePbufferSurface(mEglDisplay, eglConfig,
-                kPbufferAttribs);
-        if (mEglSurface == EGL_NO_SURFACE) {
-            ALOGW("eglCreatePbufferSurface failed: 0x%x", eglGetError());
-            return false;
-        }
-
-        mEglContext = eglCreateContext(mEglDisplay, eglConfig, EGL_NO_CONTEXT,
-                kContextAttribs);
-        if (mEglContext == EGL_NO_CONTEXT) {
-            ALOGW("eglCreateContext failed: 0x%x", eglGetError());
-            return false;
-        }
-
-        return true;
-    }
-
-    /*
-     * Releases EGL.  How we do that depends on the type of test we're
-     * running.
-     */
-    bool eglRelease_l() {
-        if (mEglDisplay == EGL_NO_DISPLAY) {
-            ALOGW("No display to release");
-            return false;
-        }
-
-        switch (mTestType) {
-        case TEST_CORRECT:
-            eglTerminate(mEglDisplay);
-            eglReleaseThread();
-            break;
-        case TEST_NO_RELEASE_CURRENT:
-            eglDestroyContext(mEglDisplay, mEglContext);
-            eglDestroySurface(mEglDisplay, mEglSurface);
-            eglTerminate(mEglDisplay);
-            break;
-        default:
-            ALOGE("Unknown test type %d", mTestType);
-            break;
-        }
-
-        int err = eglGetError();
-        if (err != EGL_SUCCESS) {
-            ALOGW("eglRelease failed: 0x%x", err);
-            return false;
-        }
-        return true;
-    }
-};
-
-
-/* do things correctly */
-TEST_F(EGLCleanupTest, TestCorrect) {
-    ALOGI("Starting TEST_CORRECT");
-    ChainedThread cht(ChainedThread::TEST_CORRECT);
-
-    // start initial thread
-    ASSERT_TRUE(cht.start());
-
-    // wait for the end
-    cht.waitForEnd();
-    bool result = cht.getResult();
-    ASSERT_TRUE(result);
-}
-
-/* try it without un-currenting the surfaces and context
-TEST _F(EGLCleanupTest, TestNoReleaseCurrent) {
-    ALOGI("Starting TEST_NO_RELEASE_CURRENT");
-    ChainedThread cht(ChainedThread::TEST_NO_RELEASE_CURRENT);
-
-    // start initial thread
-    ASSERT_TRUE(cht.start());
-
-    // wait for the end
-    cht.waitForEnd();
-    bool result = cht.getResult();
-    ASSERT_TRUE(result);
-}
-*/
-
-} // namespace android
diff --git a/tests/tests/nativeopengl/standalone/jni/tests/EGLCreateContext_test.cpp b/tests/tests/nativeopengl/standalone/jni/tests/EGLCreateContext_test.cpp
deleted file mode 100644
index b7e5f7c..0000000
--- a/tests/tests/nativeopengl/standalone/jni/tests/EGLCreateContext_test.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#include <android/native_window.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-
-#include <gtest/gtest.h>
-
-#include <android/log.h>
-
-#include "GLTestHelper.h"
-
-#define LOG_TAG "EGLCreateContext_test"
-#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
-#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
-
-namespace android {
-
-static int getGlVersion() {
-    const char* s = (const char*)glGetString(GL_VERSION);
-    if (!s)
-        return 0;
-    int major, minor;
-    if (sscanf(s, "OpenGL ES %d.%d", &major, &minor) != 2)
-        return 0;
-    return major;
-}
-
-class EGLCreateContextTest : public ::testing::Test {
-
-protected:
-
-    EGLCreateContextTest()
-    :   mEglDisplay(EGL_NO_DISPLAY),
-        mEglConfig(0),
-        mEglWindowSurface(EGL_NO_SURFACE),
-        mEglContext(EGL_NO_CONTEXT)
-    {}
-
-    virtual void SetUp() {
-        // static const EGLint SURFACE_ATTRIBS[] = {
-        //     EGL_NONE
-        // };
-
-        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
-
-        EGLint major, minor;
-        ASSERT_TRUE(eglInitialize(mEglDisplay, &major, &minor));
-
-        EGLint numConfigs = 0;
-        ASSERT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(),
-                &mEglConfig, 1, &numConfigs));
-        ASSERT_GE(1, numConfigs);
-        ASSERT_NE((EGLConfig)0, mEglConfig);
-
-        mEglWindowSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig,
-                GLTestHelper::getWindow(), getWindowSurfaceAttribs());
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_SURFACE, mEglWindowSurface);
-    }
-
-    virtual void TearDown() {
-        if (mEglContext != EGL_NO_CONTEXT) {
-            eglDestroyContext(mEglDisplay, mEglContext);
-        }
-        if (mEglWindowSurface != EGL_NO_SURFACE) {
-            eglDestroySurface(mEglDisplay, mEglWindowSurface);
-        }
-        if (mEglDisplay != EGL_NO_DISPLAY) {
-            eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
-                    EGL_NO_CONTEXT);
-            eglTerminate(mEglDisplay);
-        }
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    }
-
-    virtual const EGLint* getConfigAttribs() {
-        static const EGLint ATTRIBS[] = {
-            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-            EGL_RED_SIZE, 8,
-            EGL_GREEN_SIZE, 8,
-            EGL_BLUE_SIZE, 8,
-            EGL_ALPHA_SIZE, 8,
-            EGL_NONE
-        };
-        return ATTRIBS;
-    }
-
-    virtual const EGLint* getWindowSurfaceAttribs() {
-        return NULL;
-    }
-
-    EGLDisplay mEglDisplay;
-    EGLConfig  mEglConfig;
-    EGLSurface mEglWindowSurface;
-    EGLContext mEglContext;
-};
-
-TEST_F(EGLCreateContextTest, BadAttributeFails) {
-    // First check that we can successfully create a context
-    EGLint attribs[5] = {
-        EGL_CONTEXT_CLIENT_VERSION, 2,
-        EGL_NONE, EGL_NONE, EGL_NONE,
-    };
-    mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT,
-            attribs);
-    ASSERT_NE(mEglContext, EGL_NO_CONTEXT);
-    ASSERT_EQ(eglGetError(), EGL_SUCCESS);
-    ASSERT_EQ(EGL_TRUE, eglDestroyContext(mEglDisplay, mEglContext));
-    mEglContext = EGL_NO_CONTEXT;
-
-    // Now add an invalid attribute and make sure eglCreateContext fails
-    attribs[2] = EGL_BAD_ATTRIBUTE; // error code, not a valid attribute
-    mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT,
-            attribs);
-    ASSERT_EQ(mEglContext, EGL_NO_CONTEXT);
-    ASSERT_EQ(eglGetError(), EGL_BAD_ATTRIBUTE);
-}
-
-} // namespace android
diff --git a/tests/tests/nativeopengl/standalone/jni/tests/GLTest_test.cpp b/tests/tests/nativeopengl/standalone/jni/tests/GLTest_test.cpp
deleted file mode 100644
index 5df090d..0000000
--- a/tests/tests/nativeopengl/standalone/jni/tests/GLTest_test.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright 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.
- */
-
-
-#include <android/native_window.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#include <gtest/gtest.h>
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <GLTestHelper.h>
-
-
-namespace android {
-
-class GLTest : public ::testing::Test {
-
-protected:
-
-    GLTest():
-            mEglDisplay(EGL_NO_DISPLAY),
-            mEglSurface(EGL_NO_SURFACE),
-            mEglContext(EGL_NO_CONTEXT) {
-    }
-
-
-   virtual void SetUp() {
-        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
-
-        EGLint majorVersion;
-        EGLint minorVersion;
-        EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-        EGLint numConfigs = 0;
-        EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mGlConfig,
-                1, &numConfigs));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-        char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
-        if (displaySecsEnv != NULL) {
-            mDisplaySecs = atoi(displaySecsEnv);
-            if (mDisplaySecs < 0) {
-                mDisplaySecs = 0;
-            }
-        } else {
-            mDisplaySecs = 0;
-        }
-
-        if (mDisplaySecs > 0) {
-            mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
-                    GLTestHelper::getWindow(), NULL);
-        } else {
-            EGLint pbufferAttribs[] = {
-                EGL_WIDTH, getSurfaceWidth(),
-                EGL_HEIGHT, getSurfaceHeight(),
-                EGL_NONE };
-
-            mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig,
-                    pbufferAttribs);
-        }
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
-
-        mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT,
-                getContextAttribs());
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
-
-        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
-                mEglContext));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-        EGLint w, h;
-        EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-        glViewport(0, 0, w, h);
-        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-    }
-
-    virtual void TearDown() {
-        // Display the result
-        if (mDisplaySecs > 0 && mEglSurface != EGL_NO_SURFACE) {
-            eglSwapBuffers(mEglDisplay, mEglSurface);
-            sleep(mDisplaySecs);
-        }
-
-        if (mEglContext != EGL_NO_CONTEXT) {
-            eglDestroyContext(mEglDisplay, mEglContext);
-        }
-        if (mEglSurface != EGL_NO_SURFACE) {
-            eglDestroySurface(mEglDisplay, mEglSurface);
-        }
-        if (mEglDisplay != EGL_NO_DISPLAY) {
-            eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
-                    EGL_NO_CONTEXT);
-            eglTerminate(mEglDisplay);
-        }
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    }
-
-    virtual EGLint const* getConfigAttribs() {
-        static EGLint sDefaultConfigAttribs[] = {
-            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
-            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-            EGL_RED_SIZE, 8,
-            EGL_GREEN_SIZE, 8,
-            EGL_BLUE_SIZE, 8,
-            EGL_ALPHA_SIZE, 8,
-            EGL_DEPTH_SIZE, 16,
-            EGL_STENCIL_SIZE, 8,
-            EGL_NONE };
-
-        return sDefaultConfigAttribs;
-    }
-
-    virtual EGLint const* getContextAttribs() {
-        static EGLint sDefaultContextAttribs[] = {
-            EGL_CONTEXT_CLIENT_VERSION, 2,
-            EGL_NONE };
-
-        return sDefaultContextAttribs;
-    }
-
-    virtual EGLint getSurfaceWidth() {
-        return 512;
-    }
-
-    virtual EGLint getSurfaceHeight() {
-        return 512;
-    }
-
-    bool checkPixel(GLubyte * actual, GLubyte * expected, int tolerance) {
-        for (int i = 0; i < 4; i++) {
-            if (abs(actual[i] - expected[i]) > tolerance) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    ::testing::AssertionResult AssertPixel(const char* a_expr,
-            const char* e_expr, const char* t_expr, GLubyte * actual,
-            GLubyte * expected, int tolerance) {
-
-        if (checkPixel(actual, expected, tolerance)) {
-            return ::testing::AssertionSuccess();
-        }
-
-        return ::testing::AssertionFailure()
-            << "Pixel comparison failed with tolerance " << tolerance << "\n"
-            << "Actual: r=" << (int)actual[0] << " g=" << (int)actual[1]
-            << " b=" << (int)actual[2] << " a=" << (int)actual[3] << "\n"
-            << "Expected: r=" << (int)expected[0] << " g=" << (int)expected[1]
-            << " b=" << (int)expected[2] << " a=" << (int)expected[3] << "\n";
-    }
-
-    int mDisplaySecs;
-
-    EGLDisplay mEglDisplay;
-    EGLSurface mEglSurface;
-    EGLContext mEglContext;
-    EGLConfig  mGlConfig;
-};
-
-TEST_F(GLTest, ClearColorTest) {
-    glClearColor(0.2, 0.2, 0.2, 0.2);
-    glClear(GL_COLOR_BUFFER_BIT);
-    GLubyte expected[4] = { 51, 51, 51, 51 };
-    GLubyte pixel[4];
-    glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
-    ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-    ASSERT_PRED_FORMAT3(AssertPixel, pixel, expected, 2);
-}
-
-} // namespace android
diff --git a/tests/tests/nativeopengl/standalone/src/com/android/gltest/GLTestActivity.java b/tests/tests/nativeopengl/standalone/src/com/android/gltest/GLTestActivity.java
deleted file mode 100644
index f0c250b..0000000
--- a/tests/tests/nativeopengl/standalone/src/com/android/gltest/GLTestActivity.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 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.gltest;
-
-import android.app.Activity;
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.Surface;
-
-public class GLTestActivity extends Activity {
-
-    private class TestThread extends Thread {
-
-        public void run() {
-            // it is possible to set the GTest filter flag from here
-            // for example "GLTest.ClearColorTest" to run that specific test only
-            runTests(null);
-
-            try {
-                Thread.sleep(1000);
-            } catch (InterruptedException e) {
-            }
-
-            finish();
-            System.exit(0);
-        }
-    }
-
-    private SurfaceView mSurfaceView;
-
-    private SurfaceHolder.Callback mHolderCallback = new SurfaceHolder.Callback() {
-
-        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-            setSurface(holder.getSurface());
-        }
-
-        public void surfaceCreated(SurfaceHolder holder) {
-            setSurface(holder.getSurface());
-            Thread t = new TestThread();
-            t.start();
-        }
-
-        public void surfaceDestroyed(SurfaceHolder holder) {
-        }
-    };
-
-    @SuppressWarnings("deprecation")
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        if (checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
-                == PackageManager.PERMISSION_GRANTED) {
-            KeyguardManager keyguardManager =
-                (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
-            keyguardManager.newKeyguardLock("gltest").disableKeyguard();
-        }
-
-        super.onCreate(savedInstanceState);
-
-        mSurfaceView = new SurfaceView(this);
-        mSurfaceView.getHolder().addCallback(mHolderCallback);
-        setContentView(mSurfaceView);
-        System.loadLibrary("stlport_shared");
-        System.loadLibrary("nativeopengltests");
-    }
-
-    private static native void setSurface(Surface surface);
-    private static native void runTests(String filter);
-}
diff --git a/tests/tests/ndef/Android.mk b/tests/tests/ndef/Android.mk
index ba78f29..0c93e80 100644
--- a/tests/tests/ndef/Android.mk
+++ b/tests/tests/ndef/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/ndef/AndroidManifest.xml b/tests/tests/ndef/AndroidManifest.xml
index e0244e1..dcec27d 100644
--- a/tests/tests/ndef/AndroidManifest.xml
+++ b/tests/tests/ndef/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.ndef">
+    package="android.ndef.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -24,7 +24,7 @@
 
     <!-- This is a self-instrumenting test package. -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.ndef"
+                     android:targetPackage="android.ndef.cts"
                      android:label="CTS tests of NDEF data classes">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/ndef/AndroidTest.xml b/tests/tests/ndef/AndroidTest.xml
new file mode 100644
index 0000000..cfb40d3
--- /dev/null
+++ b/tests/tests/ndef/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS NDEF test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsNdefTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.ndef.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/net/Android.mk b/tests/tests/net/Android.mk
index 6524871..716141d 100644
--- a/tests/tests/net/Android.mk
+++ b/tests/tests/net/Android.mk
@@ -40,6 +40,9 @@
 # uncomment when b/13249961 is fixed
 #LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/net/AndroidManifest.xml b/tests/tests/net/AndroidManifest.xml
index 001e294..2bc8216 100644
--- a/tests/tests/net/AndroidManifest.xml
+++ b/tests/tests/net/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.net">
+    package="android.net.cts">
 
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -35,7 +35,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.net"
+                     android:targetPackage="android.net.cts"
                      android:label="CTS tests of android.net">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/net/AndroidTest.xml b/tests/tests/net/AndroidTest.xml
new file mode 100644
index 0000000..dc80339
--- /dev/null
+++ b/tests/tests/net/AndroidTest.xml
@@ -0,0 +1,25 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Net test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.WifiCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsNetTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.net.cts" />
+        <option name="runtime-hint" value="9m4s" />
+    </test>
+</configuration>
diff --git a/tests/tests/opengl/Android.mk b/tests/tests/opengl/Android.mk
index 3844807..4b02263 100644
--- a/tests/tests/opengl/Android.mk
+++ b/tests/tests/opengl/Android.mk
@@ -35,10 +35,10 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
 
 # Include the associated library's makefile.
 include $(LOCAL_PATH)/libopengltest/Android.mk
-
-
-
diff --git a/tests/tests/opengl/AndroidManifest.xml b/tests/tests/opengl/AndroidManifest.xml
index 363b9aa..cc0ab8f 100644
--- a/tests/tests/opengl/AndroidManifest.xml
+++ b/tests/tests/opengl/AndroidManifest.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.opengl"
+    package="android.opengl.cts"
     android:versionCode="1"
     android:versionName="1.0" >
 
@@ -23,7 +23,7 @@
     <uses-feature android:glEsVersion="0x00020000"/>
     <instrumentation
         android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.cts.opengl" >
+        android:targetPackage="android.opengl.cts" >
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/opengl/AndroidTest.xml b/tests/tests/opengl/AndroidTest.xml
new file mode 100644
index 0000000..124d072
--- /dev/null
+++ b/tests/tests/opengl/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS OpenGL test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsOpenGLTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.opengl.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/openglperf/Android.mk b/tests/tests/openglperf/Android.mk
index 6b42ed0..cb9ad8f 100644
--- a/tests/tests/openglperf/Android.mk
+++ b/tests/tests/openglperf/Android.mk
@@ -36,6 +36,9 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
 
 # Make the replica island app and copy it to CTS out dir.
diff --git a/tests/tests/openglperf/AndroidManifest.xml b/tests/tests/openglperf/AndroidManifest.xml
index a213e51..9335a65 100644
--- a/tests/tests/openglperf/AndroidManifest.xml
+++ b/tests/tests/openglperf/AndroidManifest.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.openglperf"
+    package="android.openglperf.cts"
     android:versionCode="1"
     android:versionName="1.0" >
 
@@ -32,7 +32,7 @@
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
     <instrumentation
-        android:targetPackage="com.android.cts.openglperf"
+        android:targetPackage="android.openglperf.cts"
         android:name="android.support.test.runner.AndroidJUnitRunner">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/openglperf/AndroidTest.xml b/tests/tests/openglperf/AndroidTest.xml
new file mode 100644
index 0000000..630bd05
--- /dev/null
+++ b/tests/tests/openglperf/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS OpenGL Performance test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsOpenGlPerfTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.openglperf.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/openglperf/jni/Android.mk b/tests/tests/openglperf/jni/Android.mk
index 2cebaec..f67900c 100644
--- a/tests/tests/openglperf/jni/Android.mk
+++ b/tests/tests/openglperf/jni/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) $(call include-path-for, system-core) frameworks/native/opengl/include
 
-LOCAL_SHARED_LIBRARIES := libnativehelper libcutils liblog libGLES_trace libEGL
+LOCAL_SHARED_LIBRARIES := libnativehelper libcutils liblog libEGL
 
 LOCAL_SDK_VERSION := 14
 
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index f4b140e..6a2f8f8 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -36,6 +36,9 @@
 
 LOCAL_PACKAGE_NAME := CtsOsTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # uncomment when b/13282254 is fixed
 #LOCAL_SDK_VERSION := current
 LOCAL_JAVA_LIBRARIES += android.test.runner
diff --git a/tests/tests/os/AndroidTest.xml b/tests/tests/os/AndroidTest.xml
new file mode 100644
index 0000000..1676c88
--- /dev/null
+++ b/tests/tests/os/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for OS Tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsOsTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.cts.os" />
+        <option name="runtime-hint" value="3m15s" />
+    </test>
+</configuration>
diff --git a/tests/tests/os/src/android/os/cts/MessengerTest.java b/tests/tests/os/src/android/os/cts/MessengerTest.java
index 72bf247..5bf9428 100644
--- a/tests/tests/os/src/android/os/cts/MessengerTest.java
+++ b/tests/tests/os/src/android/os/cts/MessengerTest.java
@@ -30,6 +30,7 @@
 import android.os.Messenger;
 import android.os.Parcel;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.test.AndroidTestCase;
 
 import java.io.FileDescriptor;
@@ -88,6 +89,11 @@
         public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
         }
 
+        @Override
+        public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+                String[] args, ResultReceiver resultReceiver) {
+        }
+
     };
 
     // Create another messenger to send msg.
diff --git a/tests/tests/permission/Android.mk b/tests/tests/permission/Android.mk
index 6a7da5f..58c4f08 100644
--- a/tests/tests/permission/Android.mk
+++ b/tests/tests/permission/Android.mk
@@ -19,6 +19,11 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
diff --git a/tests/tests/permission/AndroidManifest.xml b/tests/tests/permission/AndroidManifest.xml
index fa03335..8b08009 100644
--- a/tests/tests/permission/AndroidManifest.xml
+++ b/tests/tests/permission/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.permission">
+    package="android.permission.cts">
 
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <application>
@@ -41,8 +41,8 @@
         relies on hidden APIs.
     -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.permission"
-                     android:label="CTS tests of com.android.cts.permission">
+                     android:targetPackage="android.permission.cts"
+                     android:label="CTS tests of android.permission">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/permission/AndroidTest.xml b/tests/tests/permission/AndroidTest.xml
new file mode 100644
index 0000000..f64db70
--- /dev/null
+++ b/tests/tests/permission/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Permission test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsPermissionTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.permission.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index 6fb6a41..7096757 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -263,6 +263,20 @@
     }
 
     @MediumTest
+    public void testProcSelfPagemapNotAccessible() {
+        // Note: can't use f.canRead() here, since the security check is done
+        // during the open() process. access(R_OK) return OK even through
+        // open() eventually fails.
+        try {
+            new FileInputStream("/proc/self/pagemap");
+            fail("Device is missing the following kernel security patch: "
+                 + "https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=ab676b7d6fbf4b294bf198fb27ade5b0e865c7ce");
+        } catch (FileNotFoundException e) {
+            // expected
+        }
+    }
+
+    @MediumTest
     public void testTcpDefaultRwndSane() throws Exception {
         File f = new File("/proc/sys/net/ipv4/tcp_default_init_rwnd");
         assertTrue(f.canRead());
diff --git a/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java
index 91ffdf4..72b5530 100644
--- a/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java
@@ -38,7 +38,7 @@
     private PermissionStubActivity mActivity;
 
     public NoActivityRelatedPermissionTest() {
-        super("com.android.cts.permission", PermissionStubActivity.class);
+        super("android.permission.cts", PermissionStubActivity.class);
     }
 
     @Override
diff --git a/tests/tests/permission/src/android/permission/cts/RebootPermissionTest.java b/tests/tests/permission/src/android/permission/cts/RebootPermissionTest.java
index 4d54098..2c6e08e 100644
--- a/tests/tests/permission/src/android/permission/cts/RebootPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/RebootPermissionTest.java
@@ -40,6 +40,7 @@
     public void testBroadcastReboot() {
         try {
             mContext.sendBroadcast(new Intent(Intent.ACTION_REBOOT));
+            fail("SecurityException expected!");
         } catch (SecurityException e) {
             // expected
         }
diff --git a/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java b/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
index 607f301..cfafd9a 100644
--- a/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
@@ -17,6 +17,7 @@
 package android.permission.cts;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.media.AudioManager;
 import android.telephony.TelephonyManager;
@@ -61,6 +62,12 @@
         } catch (SecurityException e) {
             // expected
         }
+        try {
+            String id = mTelephonyManager.getDeviceId(0);
+            fail("Got device ID: " + id);
+        } catch (SecurityException e) {
+            // expected
+        }
     }
 
     /**
@@ -159,4 +166,50 @@
         mAudioManager.setMode(AudioManager.MODE_IN_CALL);
         assertEquals(audioMode, mAudioManager.getMode());
     }
+
+    /**
+     * Verify that Telephony related broadcasts are protected.
+     */
+    @SmallTest
+    public void testProtectedBroadcasts() {
+        try {
+            Intent intent = new Intent("android.intent.action.SIM_STATE_CHANGED");
+            getContext().sendBroadcast(intent);
+            fail("SecurityException expected!");
+        } catch (SecurityException e) {}
+        try {
+            Intent intent = new Intent("android.intent.action.SERVICE_STATE");
+            getContext().sendBroadcast(intent);
+            fail("SecurityException expected!");
+        } catch (SecurityException e) {}
+        try {
+            Intent intent = new Intent("android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED");
+            getContext().sendBroadcast(intent);
+            fail("SecurityException expected!");
+        } catch (SecurityException e) {}
+        try {
+            Intent intent = new Intent(
+                    "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED");
+            getContext().sendBroadcast(intent);
+            fail("SecurityException expected!");
+        } catch (SecurityException e) {}
+        try {
+            Intent intent = new Intent(
+                    "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED");
+            getContext().sendBroadcast(intent);
+            fail("SecurityException expected!");
+        } catch (SecurityException e) {}
+        try {
+            Intent intent = new Intent(
+                    "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED");
+            getContext().sendBroadcast(intent);
+            fail("SecurityException expected!");
+        } catch (SecurityException e) {}
+        try {
+            Intent intent = new Intent("android.intent.action.SIG_STR");
+            getContext().sendBroadcast(intent);
+            fail("SecurityException expected!");
+        } catch (SecurityException e) {}
+
+    }
 }
diff --git a/tests/tests/permission2/Android.mk b/tests/tests/permission2/Android.mk
index 29d5e03..3378cd9 100755
--- a/tests/tests/permission2/Android.mk
+++ b/tests/tests/permission2/Android.mk
@@ -19,6 +19,11 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_JAVA_LIBRARIES := telephony-common
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
diff --git a/tests/tests/permission2/AndroidManifest.xml b/tests/tests/permission2/AndroidManifest.xml
index 984d124..6429dab 100755
--- a/tests/tests/permission2/AndroidManifest.xml
+++ b/tests/tests/permission2/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.permission2">
+    package="android.permission2.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -63,7 +63,7 @@
             android:maxSdkVersion="9000" />
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.permission2"
+                     android:targetPackage="android.permission2.cts"
                      android:label="More CTS tests for permissions">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/permission2/AndroidTest.xml b/tests/tests/permission2/AndroidTest.xml
new file mode 100644
index 0000000..b814aa7
--- /dev/null
+++ b/tests/tests/permission2/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Permission test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsPermission2TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.permission2.cts" />
+        <option name="runtime-hint" value="2m" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/preference/Android.mk b/tests/tests/preference/Android.mk
index 7534641..398571f 100644
--- a/tests/tests/preference/Android.mk
+++ b/tests/tests/preference/Android.mk
@@ -20,6 +20,9 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/preference/AndroidManifest.xml b/tests/tests/preference/AndroidManifest.xml
index 3cc3ef8..e5fd710 100644
--- a/tests/tests/preference/AndroidManifest.xml
+++ b/tests/tests/preference/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.preference">
+    package="android.preference.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -28,8 +28,8 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.preference"
-                     android:label="CTS tests of android.os">
+                     android:targetPackage="android.preference.cts"
+                     android:label="CTS tests of android.preference">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/preference/AndroidTest.xml b/tests/tests/preference/AndroidTest.xml
new file mode 100644
index 0000000..f9074fe
--- /dev/null
+++ b/tests/tests/preference/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Preference test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsPreferenceTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.preference.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/preference/src/android/preference/cts/PreferenceActivityTest.java b/tests/tests/preference/src/android/preference/cts/PreferenceActivityTest.java
index 51ebc7d..162f200 100644
--- a/tests/tests/preference/src/android/preference/cts/PreferenceActivityTest.java
+++ b/tests/tests/preference/src/android/preference/cts/PreferenceActivityTest.java
@@ -16,7 +16,7 @@
 
 package android.preference.cts;
 
-import com.android.cts.preference.R;
+import android.preference.cts.R;
 
 import android.content.Intent;
 import android.preference.PreferenceActivity;
@@ -69,4 +69,4 @@
 
         assertEquals(prefScreen, mActivity.getPreferenceScreen());
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/preference2/Android.mk b/tests/tests/preference2/Android.mk
index 59fedc8..8dabf2c 100644
--- a/tests/tests/preference2/Android.mk
+++ b/tests/tests/preference2/Android.mk
@@ -22,6 +22,9 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/preference2/AndroidManifest.xml b/tests/tests/preference2/AndroidManifest.xml
index 2dbd53a..8d2b823 100644
--- a/tests/tests/preference2/AndroidManifest.xml
+++ b/tests/tests/preference2/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.preference2">
+    package="android.preference2.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -36,8 +36,8 @@
 
     <!-- This is a self-instrumenting test package. -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.preference2"
-                     android:label="CTS Test Cases for android.preference">
+                     android:targetPackage="android.preference2.cts"
+                     android:label="CTS Test Cases for android.preference2">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/preference2/AndroidTest.xml b/tests/tests/preference2/AndroidTest.xml
new file mode 100644
index 0000000..96dfe0e
--- /dev/null
+++ b/tests/tests/preference2/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Preference test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsPreference2TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.preference2.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/preference2/res/xml/pref_cb.xml b/tests/tests/preference2/res/xml/pref_cb.xml
index b5f77b9..73dc3d8 100755
--- a/tests/tests/preference2/res/xml/pref_cb.xml
+++ b/tests/tests/preference2/res/xml/pref_cb.xml
@@ -13,7 +13,7 @@
      limitations under the License.

 -->

 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"

-    xmlns:in="http://schemas.android.com/apk/res/com.android.cts.preference2" >

+    xmlns:in="http://schemas.android.com/apk/res/android.preference2.cts" >

 

     <PreferenceCategory android:title="@string/inline_preferences" >

         <android.preference2.cts.CustomCheckBoxPreference

diff --git a/tests/tests/preference2/src/android/preference2/cts/CheckBoxPreferenceTest.java b/tests/tests/preference2/src/android/preference2/cts/CheckBoxPreferenceTest.java
index de129e0..cf8bfde 100644
--- a/tests/tests/preference2/src/android/preference2/cts/CheckBoxPreferenceTest.java
+++ b/tests/tests/preference2/src/android/preference2/cts/CheckBoxPreferenceTest.java
@@ -19,7 +19,7 @@
 import android.preference.CheckBoxPreference;
 import android.test.ActivityInstrumentationTestCase2;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 public class CheckBoxPreferenceTest
         extends ActivityInstrumentationTestCase2<PreferenceFromCodeActivity> {
diff --git a/tests/tests/preference2/src/android/preference2/cts/CustomCheckBoxPreference.java b/tests/tests/preference2/src/android/preference2/cts/CustomCheckBoxPreference.java
index d51eddd..64cc360 100644
--- a/tests/tests/preference2/src/android/preference2/cts/CustomCheckBoxPreference.java
+++ b/tests/tests/preference2/src/android/preference2/cts/CustomCheckBoxPreference.java
@@ -15,7 +15,7 @@
  */
 package android.preference2.cts;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/tests/tests/preference2/src/android/preference2/cts/CustomDialogPreference.java b/tests/tests/preference2/src/android/preference2/cts/CustomDialogPreference.java
index db584ac..20346b1 100644
--- a/tests/tests/preference2/src/android/preference2/cts/CustomDialogPreference.java
+++ b/tests/tests/preference2/src/android/preference2/cts/CustomDialogPreference.java
@@ -15,7 +15,7 @@
  */
 package android.preference2.cts;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/tests/tests/preference2/src/android/preference2/cts/CustomEditTextPreference.java b/tests/tests/preference2/src/android/preference2/cts/CustomEditTextPreference.java
index 51fdf13..007f475 100644
--- a/tests/tests/preference2/src/android/preference2/cts/CustomEditTextPreference.java
+++ b/tests/tests/preference2/src/android/preference2/cts/CustomEditTextPreference.java
@@ -15,7 +15,7 @@
  */
 package android.preference2.cts;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/tests/tests/preference2/src/android/preference2/cts/CustomPreference.java b/tests/tests/preference2/src/android/preference2/cts/CustomPreference.java
index 7506bd0..4875acc1 100644
--- a/tests/tests/preference2/src/android/preference2/cts/CustomPreference.java
+++ b/tests/tests/preference2/src/android/preference2/cts/CustomPreference.java
@@ -15,7 +15,7 @@
  */
 package android.preference2.cts;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/tests/tests/preference2/src/android/preference2/cts/CustomPreferenceGroup.java b/tests/tests/preference2/src/android/preference2/cts/CustomPreferenceGroup.java
index 26e1bcf..c4771d3 100644
--- a/tests/tests/preference2/src/android/preference2/cts/CustomPreferenceGroup.java
+++ b/tests/tests/preference2/src/android/preference2/cts/CustomPreferenceGroup.java
@@ -15,7 +15,7 @@
  */
 package android.preference2.cts;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/tests/tests/preference2/src/android/preference2/cts/CustomSwitchPreference.java b/tests/tests/preference2/src/android/preference2/cts/CustomSwitchPreference.java
index 54e7861..6793c50 100644
--- a/tests/tests/preference2/src/android/preference2/cts/CustomSwitchPreference.java
+++ b/tests/tests/preference2/src/android/preference2/cts/CustomSwitchPreference.java
@@ -16,7 +16,7 @@
 package android.preference2.cts;
 
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/tests/tests/preference2/src/android/preference2/cts/DialogPreferenceTest.java b/tests/tests/preference2/src/android/preference2/cts/DialogPreferenceTest.java
index 1136cee..edcef0c 100644
--- a/tests/tests/preference2/src/android/preference2/cts/DialogPreferenceTest.java
+++ b/tests/tests/preference2/src/android/preference2/cts/DialogPreferenceTest.java
@@ -20,7 +20,7 @@
 import android.preference.DialogPreference;
 import android.test.ActivityInstrumentationTestCase2;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 public class DialogPreferenceTest
         extends ActivityInstrumentationTestCase2<PreferenceFromCodeActivity> {
diff --git a/tests/tests/preference2/src/android/preference2/cts/FragmentPreferences.java b/tests/tests/preference2/src/android/preference2/cts/FragmentPreferences.java
index dacc192..7efbe76 100644
--- a/tests/tests/preference2/src/android/preference2/cts/FragmentPreferences.java
+++ b/tests/tests/preference2/src/android/preference2/cts/FragmentPreferences.java
@@ -16,7 +16,7 @@
 
 package android.preference2.cts;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/preference2/src/android/preference2/cts/ListPreferenceTest.java b/tests/tests/preference2/src/android/preference2/cts/ListPreferenceTest.java
index 32596ff..743b51e 100644
--- a/tests/tests/preference2/src/android/preference2/cts/ListPreferenceTest.java
+++ b/tests/tests/preference2/src/android/preference2/cts/ListPreferenceTest.java
@@ -19,7 +19,7 @@
 import android.preference.ListPreference;
 import android.test.ActivityInstrumentationTestCase2;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 public class ListPreferenceTest
         extends ActivityInstrumentationTestCase2<PreferenceFromCodeActivity> {
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferenceFromCodeActivity.java b/tests/tests/preference2/src/android/preference2/cts/PreferenceFromCodeActivity.java
index e76c95a..7a67e3e 100644
--- a/tests/tests/preference2/src/android/preference2/cts/PreferenceFromCodeActivity.java
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferenceFromCodeActivity.java
@@ -16,7 +16,7 @@
 
 package android.preference2.cts;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 import android.os.Bundle;
 import android.preference.CheckBoxPreference;
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferenceGroupTest.java b/tests/tests/preference2/src/android/preference2/cts/PreferenceGroupTest.java
index 109ea77..fe0b3b2 100644
--- a/tests/tests/preference2/src/android/preference2/cts/PreferenceGroupTest.java
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferenceGroupTest.java
@@ -16,7 +16,7 @@
 
 package android.preference2.cts;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 import android.preference.CheckBoxPreference;
 import android.preference.EditTextPreference;
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferenceTest.java b/tests/tests/preference2/src/android/preference2/cts/PreferenceTest.java
index 328e074..b2907f3 100644
--- a/tests/tests/preference2/src/android/preference2/cts/PreferenceTest.java
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferenceTest.java
@@ -22,7 +22,7 @@
 import android.preference.PreferenceGroup;
 import android.test.ActivityInstrumentationTestCase2;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 public class PreferenceTest
         extends ActivityInstrumentationTestCase2<PreferenceFromCodeActivity> {
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferenceWithHeaders.java b/tests/tests/preference2/src/android/preference2/cts/PreferenceWithHeaders.java
index 1bb5637..a44cb7e6 100644
--- a/tests/tests/preference2/src/android/preference2/cts/PreferenceWithHeaders.java
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferenceWithHeaders.java
@@ -20,7 +20,7 @@
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceFragment;
 import android.widget.Button;
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 import java.util.List;
 
 /**
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferencesFromXml.java b/tests/tests/preference2/src/android/preference2/cts/PreferencesFromXml.java
index 0a61461..1aff9f5 100644
--- a/tests/tests/preference2/src/android/preference2/cts/PreferencesFromXml.java
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferencesFromXml.java
@@ -16,7 +16,7 @@
 
 package android.preference2.cts;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 import android.os.Bundle;
 import android.preference.PreferenceActivity;
 
diff --git a/tests/tests/preference2/src/android/preference2/cts/SwitchPreferenceTest.java b/tests/tests/preference2/src/android/preference2/cts/SwitchPreferenceTest.java
index 3bd42d2..218c55a 100644
--- a/tests/tests/preference2/src/android/preference2/cts/SwitchPreferenceTest.java
+++ b/tests/tests/preference2/src/android/preference2/cts/SwitchPreferenceTest.java
@@ -20,7 +20,7 @@
 import android.preference.SwitchPreference;
 import android.test.ActivityInstrumentationTestCase2;
 
-import com.android.cts.preference2.R;
+import android.preference2.cts.R;
 
 public class SwitchPreferenceTest
         extends ActivityInstrumentationTestCase2<PreferenceFromCodeActivity> {
diff --git a/tests/tests/print/Android.mk b/tests/tests/print/Android.mk
index 2ece2cf..211b5ee 100644
--- a/tests/tests/print/Android.mk
+++ b/tests/tests/print/Android.mk
@@ -18,12 +18,17 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsPrintTestCases
 
 LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner ub-uiautomator ctsdeviceutil
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := test_current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/print/AndroidManifest.xml b/tests/tests/print/AndroidManifest.xml
index b4a2905..c7edf6d 100644
--- a/tests/tests/print/AndroidManifest.xml
+++ b/tests/tests/print/AndroidManifest.xml
@@ -17,7 +17,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.print">
+        package="android.print.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
 
@@ -72,7 +72,7 @@
   </application>
 
   <instrumentation android:name="android.support.test.uiautomator.UiAutomatorInstrumentationTestRunner"
-          android:targetPackage="com.android.cts.print"
+          android:targetPackage="android.print.cts"
           android:label="Tests for the print APIs."/>
 
 </manifest>
diff --git a/tests/tests/print/AndroidTest.xml b/tests/tests/print/AndroidTest.xml
new file mode 100644
index 0000000..21d8f03
--- /dev/null
+++ b/tests/tests/print/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Print test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsPrintTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.print.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/print/res/drawable/red_printer.xml b/tests/tests/print/res/drawable/red_printer.xml
new file mode 100644
index 0000000..1bd7a4f
--- /dev/null
+++ b/tests/tests/print/res/drawable/red_printer.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+    Copyright (C) 2015 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M10,18h28v13h-28z"
+        android:fillAlpha="1"
+        android:fillColor="#cccccc"
+        android:strokeColor="#00000000"/>
+    <path
+        android:pathData="M13,7L13,10L9,10C7,10 4,13 4,15L4,35L13,35L13,40L35,40L35,35L44,35L44,15C44,13 41,10 39,10L35,10L35,7L13,7zM14,8L34,8L34,10L14,10L14,8zM10,18L38,18L38,31L35,31L35,23L13,23L13,31L10,31L10,18zM14,24L34,24L34,39L14,39L14,24z"
+        android:fillColor="#0000ff"
+        android:strokeColor="#00000000"/>
+    <path
+        android:pathData="M14,24h20v15h-20z"
+        android:fillAlpha="1"
+        android:fillColor="#ffffff"
+        android:strokeColor="#00000000"/>
+    <path
+        android:pathData="M14,8h20v2h-20z"
+        android:fillAlpha="1"
+        android:fillColor="#ffffff"
+        android:strokeColor="#00000000"/>
+</vector>
diff --git a/tests/tests/print/res/raw/yellow_printer.png b/tests/tests/print/res/raw/yellow_printer.png
new file mode 100644
index 0000000..2e1cc8d
--- /dev/null
+++ b/tests/tests/print/res/raw/yellow_printer.png
Binary files differ
diff --git a/tests/tests/print/res/xml/printservice.xml b/tests/tests/print/res/xml/printservice.xml
index 5579b81..2765a39 100644
--- a/tests/tests/print/res/xml/printservice.xml
+++ b/tests/tests/print/res/xml/printservice.xml
@@ -17,6 +17,6 @@
 -->
 
 <print-service  xmlns:android="http://schemas.android.com/apk/res/android"
-     android:settingsActivity="android.print.services.SettingsActivity"
-     android:addPrintersActivity="android.print.services.AddPrintersActivity"
-     android:advancedPrintOptionsActivity="android.print.services.CustomPrintOptionsActivity"/>
+     android:settingsActivity="android.print.cts.services.SettingsActivity"
+     android:addPrintersActivity="android.print.cts.services.AddPrintersActivity"
+     android:advancedPrintOptionsActivity="android.print.cts.services.CustomPrintOptionsActivity"/>
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index 8a59c14..577e29a 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -41,19 +41,20 @@
 import android.print.PrintDocumentAdapter.WriteResultCallback;
 import android.print.PrintManager;
 import android.print.PrinterId;
-import android.print.cts.services.FirstPrintService;
 import android.print.cts.services.PrintServiceCallbacks;
 import android.print.cts.services.PrinterDiscoverySessionCallbacks;
-import android.print.cts.services.SecondPrintService;
 import android.print.cts.services.StubbablePrinterDiscoverySession;
 import android.print.pdf.PrintedPdfDocument;
+import android.printservice.CustomPrinterIconCallback;
 import android.printservice.PrintJob;
 import android.printservice.PrintService;
-import android.support.test.uiautomator.UiAutomatorTestCase;
+import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiObjectNotFoundException;
 import android.support.test.uiautomator.UiSelector;
+import android.test.InstrumentationTestCase;
 import android.util.DisplayMetrics;
+import android.util.LocaleList;
 
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
@@ -74,7 +75,7 @@
 /**
  * This is the base class for print tests.
  */
-public abstract class BasePrintTest extends UiAutomatorTestCase {
+public abstract class BasePrintTest extends InstrumentationTestCase {
 
     private static final long OPERATION_TIMEOUT = 100000000;
 
@@ -92,7 +93,18 @@
 
     private PrintDocumentActivity mActivity;
 
-    private Locale mOldLocale;
+    private UiDevice mUiDevice;
+
+    /**
+     * Return the UI device
+     *
+     * @return the UI device
+     */
+    public UiDevice getUiDevice() {
+        return mUiDevice;
+    }
+
+    private LocaleList mOldLocale;
 
     private CallCounter mCancelOperationCounter;
     private CallCounter mLayoutCallCounter;
@@ -108,12 +120,13 @@
 
         ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
                 .executeShellCommand(COMMAND_LIST_ENABLED_IME_COMPONENTS);
-        BufferedReader reader = new BufferedReader(
-                new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())));
+        try (BufferedReader reader = new BufferedReader(
+                new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())))) {
 
-        String line;
-        while ((line = reader.readLine()) != null) {
-            imeList.add(line);
+            String line;
+            while ((line = reader.readLine()) != null) {
+                imeList.add(line);
+            }
         }
 
         String[] imeArray = new String[imeList.size()];
@@ -153,9 +166,10 @@
             return;
         }
 
+        mUiDevice = UiDevice.getInstance(getInstrumentation());
+
         // Make sure we start with a clean slate.
         clearPrintSpoolerData();
-        enablePrintServices();
         disableImes();
 
         // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
@@ -166,11 +180,11 @@
         // Set to US locale.
         Resources resources = getInstrumentation().getTargetContext().getResources();
         Configuration oldConfiguration = resources.getConfiguration();
-        if (!oldConfiguration.locale.equals(Locale.US)) {
-            mOldLocale = oldConfiguration.locale;
+        if (!oldConfiguration.getLocales().getPrimary().equals(Locale.US)) {
+            mOldLocale = oldConfiguration.getLocales();
             DisplayMetrics displayMetrics = resources.getDisplayMetrics();
             Configuration newConfiguration = new Configuration(oldConfiguration);
-            newConfiguration.locale = Locale.US;
+            newConfiguration.setLocale(Locale.US);
             resources.updateConfiguration(newConfiguration, displayMetrics);
         }
 
@@ -202,30 +216,33 @@
             Resources resources = getInstrumentation().getTargetContext().getResources();
             DisplayMetrics displayMetrics = resources.getDisplayMetrics();
             Configuration newConfiguration = new Configuration(resources.getConfiguration());
-            newConfiguration.locale = mOldLocale;
+            newConfiguration.setLocales(mOldLocale);
             mOldLocale = null;
             resources.updateConfiguration(newConfiguration, displayMetrics);
         }
 
-        disablePrintServices();
-        // Make sure the spooler is cleaned.
+        // Make sure the spooler is cleaned, this also un-approves all services
         clearPrintSpoolerData();
 
         super.tearDown();
     }
 
-    protected void print(final PrintDocumentAdapter adapter) {
+    protected void print(final PrintDocumentAdapter adapter, final PrintAttributes attributes) {
         // Initiate printing as if coming from the app.
         getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 PrintManager printManager = (PrintManager) getActivity()
                         .getSystemService(Context.PRINT_SERVICE);
-                printManager.print("Print job", adapter, null);
+                printManager.print("Print job", adapter, attributes);
             }
         });
     }
 
+    protected void print(PrintDocumentAdapter adapter) {
+        print(adapter, null);
+    }
+
     protected void onCancelOperationCalled() {
         mCancelOperationCounter.call();
     }
@@ -291,12 +308,12 @@
         }
     }
 
-    protected void selectPrinter(String printerName) throws UiObjectNotFoundException {
+    protected void selectPrinter(String printerName) throws UiObjectNotFoundException, IOException {
         try {
-            UiObject destinationSpinner = new UiObject(new UiSelector().resourceId(
+            UiObject destinationSpinner = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/destination_spinner"));
             destinationSpinner.click();
-            UiObject printerOption = new UiObject(new UiSelector().text(printerName));
+            UiObject printerOption = mUiDevice.findObject(new UiSelector().text(printerName));
             printerOption.click();
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
@@ -304,12 +321,24 @@
         }
     }
 
-    protected void changeOrientation(String orientation) throws UiObjectNotFoundException {
+    protected void answerPrintServicesWarning(boolean confirm) throws UiObjectNotFoundException {
+        UiDevice uiDevice = UiDevice.getInstance(getInstrumentation());
+        UiObject button;
+        if (confirm) {
+            button = uiDevice.findObject(new UiSelector().resourceId("android:id/button1"));
+        } else {
+            button = uiDevice.findObject(new UiSelector().resourceId("android:id/button2"));
+        }
+        button.click();
+    }
+
+    protected void changeOrientation(String orientation)
+            throws UiObjectNotFoundException, IOException {
         try {
-            UiObject orientationSpinner = new UiObject(new UiSelector().resourceId(
+            UiObject orientationSpinner = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/orientation_spinner"));
             orientationSpinner.click();
-            UiObject orientationOption = new UiObject(new UiSelector().text(orientation));
+            UiObject orientationOption = mUiDevice.findObject(new UiSelector().text(orientation));
             orientationOption.click();
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
@@ -317,12 +346,12 @@
         }
     }
 
-    protected void changeMediaSize(String mediaSize) throws UiObjectNotFoundException {
+    protected void changeMediaSize(String mediaSize) throws UiObjectNotFoundException, IOException {
         try {
-            UiObject mediaSizeSpinner = new UiObject(new UiSelector().resourceId(
+            UiObject mediaSizeSpinner = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/paper_size_spinner"));
             mediaSizeSpinner.click();
-            UiObject mediaSizeOption = new UiObject(new UiSelector().text(mediaSize));
+            UiObject mediaSizeOption = mUiDevice.findObject(new UiSelector().text(mediaSize));
             mediaSizeOption.click();
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
@@ -330,12 +359,12 @@
         }
     }
 
-    protected void changeColor(String color) throws UiObjectNotFoundException {
+    protected void changeColor(String color) throws UiObjectNotFoundException, IOException {
         try {
-            UiObject colorSpinner = new UiObject(new UiSelector().resourceId(
+            UiObject colorSpinner = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/color_spinner"));
             colorSpinner.click();
-            UiObject colorOption = new UiObject(new UiSelector().text(color));
+            UiObject colorOption = mUiDevice.findObject(new UiSelector().text(color));
             colorOption.click();
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
@@ -343,12 +372,12 @@
         }
     }
 
-    protected void changeDuplex(String duplex) throws UiObjectNotFoundException {
+    protected void changeDuplex(String duplex) throws UiObjectNotFoundException, IOException {
         try {
-            UiObject duplexSpinner = new UiObject(new UiSelector().resourceId(
+            UiObject duplexSpinner = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/duplex_spinner"));
             duplexSpinner.click();
-            UiObject duplexOption = new UiObject(new UiSelector().text(duplex));
+            UiObject duplexOption = mUiDevice.findObject(new UiSelector().text(duplex));
             duplexOption.click();
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
@@ -356,9 +385,9 @@
         }
     }
 
-    protected void clickPrintButton() throws UiObjectNotFoundException {
+    protected void clickPrintButton() throws UiObjectNotFoundException, IOException {
         try {
-            UiObject printButton = new UiObject(new UiSelector().resourceId(
+            UiObject printButton = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/print_button"));
             printButton.click();
         } catch (UiObjectNotFoundException e) {
@@ -367,24 +396,26 @@
         }
     }
 
-    private void dumpWindowHierarchy() {
+    private void dumpWindowHierarchy() throws IOException {
         String name = "print-test-failure-" + System.currentTimeMillis() + ".xml";
         File file = new File(getActivity().getFilesDir(), name);
-        getUiDevice().dumpWindowHierarchy(file.toString());
+        try (FileOutputStream os = new FileOutputStream(file.toString())) {
+            mUiDevice.dumpWindowHierarchy(os);
+        }
     }
 
     protected PrintDocumentActivity getActivity() {
         return mActivity;
     }
 
-    private void createActivity() {
+    protected void createActivity() {
         mActivity = launchActivity(
                 getInstrumentation().getTargetContext().getPackageName(),
                 PrintDocumentActivity.class, null);
     }
 
     protected void openPrintOptions() throws UiObjectNotFoundException {
-        UiObject expandHandle = new UiObject(new UiSelector().resourceId(
+        UiObject expandHandle = mUiDevice.findObject(new UiSelector().resourceId(
                 "com.android.printspooler:id/expand_collapse_handle"));
         expandHandle.click();
     }
@@ -396,20 +427,6 @@
                             .contains(PM_CLEAR_SUCCESS_OUTPUT));
     }
 
-    private void enablePrintServices() throws Exception {
-        String pkgName = getInstrumentation().getContext().getPackageName();
-        String enabledServicesValue = String.format("%s/%s:%s/%s",
-                pkgName, FirstPrintService.class.getCanonicalName(),
-                pkgName, SecondPrintService.class.getCanonicalName());
-        SystemUtil.runShellCommand(getInstrumentation(),
-                "settings put secure enabled_print_services " + enabledServicesValue);
-    }
-
-    private void disablePrintServices() throws Exception {
-        SystemUtil.runShellCommand(getInstrumentation(),
-                "settings put secure enabled_print_services \"\"");
-    }
-
     protected void verifyLayoutCall(InOrder inOrder, PrintDocumentAdapter mock,
             PrintAttributes oldAttributes, PrintAttributes newAttributes,
             final boolean forPreview) {
@@ -454,7 +471,8 @@
     protected PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
             Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery,
             Answer<Void> onValidatePrinters, Answer<Void> onStartPrinterStateTracking,
-            Answer<Void> onStopPrinterStateTracking, Answer<Void> onDestroy) {
+            Answer<Void> onRequestCustomPrinterIcon, Answer<Void> onStopPrinterStateTracking,
+            Answer<Void> onDestroy) {
         PrinterDiscoverySessionCallbacks callbacks = mock(PrinterDiscoverySessionCallbacks.class);
 
         doCallRealMethod().when(callbacks).setSession(any(StubbablePrinterDiscoverySession.class));
@@ -475,6 +493,10 @@
             doAnswer(onStartPrinterStateTracking).when(callbacks).onStartPrinterStateTracking(
                     any(PrinterId.class));
         }
+        if (onRequestCustomPrinterIcon != null) {
+            doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
+                    any(PrinterId.class), any(CustomPrinterIconCallback.class));
+        }
         if (onStopPrinterStateTracking != null) {
             doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
                     any(PrinterId.class));
diff --git a/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
index b9fd50a..dcea91f 100644
--- a/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
+++ b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
@@ -146,6 +146,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -258,6 +261,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -386,6 +392,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -598,6 +607,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -667,7 +679,7 @@
 
                 return null;
             }
-        }, null, null, null, null, null);
+        }, null, null, null, null, null, null);
     }
 
     private PrintServiceCallbacks createSecondMockPrintServiceCallbacks() {
diff --git a/tests/tests/print/src/android/print/cts/PrintAttributesTest.java b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
new file mode 100644
index 0000000..855f587
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 2015 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.print.cts;
+
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.print.PrintDocumentInfo;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.print.cts.services.FirstPrintService;
+import android.print.cts.services.PrintServiceCallbacks;
+import android.print.cts.services.PrinterDiscoverySessionCallbacks;
+import android.print.cts.services.SecondPrintService;
+import android.print.cts.services.StubbablePrinterDiscoverySession;
+import android.printservice.PrintJob;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test that the print attributes are correctly propagated through the print framework
+ */
+public class PrintAttributesTest extends BasePrintTest {
+    private final String PRINTER_NAME = "Test printer";
+
+    private final Margins[] MIN_MARGINS = {
+            new Margins(0, 0, 0, 0), new Margins(10, 10, 10, 10), new Margins(20, 20, 20, 20),
+    };
+
+    private final MediaSize MEDIA_SIZES[] = {
+            MediaSize.ISO_A3, MediaSize.ISO_A4, MediaSize.ISO_A5
+    };
+
+    private final int COLOR_MODES[] = {
+            PrintAttributes.COLOR_MODE_MONOCHROME, PrintAttributes.COLOR_MODE_COLOR
+    };
+
+    private final int DUPLEX_MODES[] = {
+            PrintAttributes.DUPLEX_MODE_NONE, PrintAttributes.DUPLEX_MODE_LONG_EDGE,
+            PrintAttributes.DUPLEX_MODE_SHORT_EDGE
+    };
+
+    private final Resolution RESOLUTIONS[] = {
+            new Resolution("300x300", "300x300", 300, 300),
+            new Resolution("600x600", "600x600", 600, 600),
+            new Resolution("1200x1200", "1200x1200", 1200, 1200)
+    };
+
+    /**
+     * Stores the {@link PrintAttributes} passed to the layout method
+     */
+    private PrintAttributes mLayoutAttributes;
+
+    /**
+     * Create a new {@link PrintAttributes} object with the given properties.
+     *
+     * All properties can be null/0 to remain unset.
+     *
+     * @param mediaSize {@link MediaSize} to use
+     * @param colorMode Color mode to use
+     * @param duplexMode Duplex mode to use
+     * @param resolution {@link Resolution} to use
+     *
+     * @return The newly created object or null if no properties are set
+     */
+    private PrintAttributes createAttributes(MediaSize mediaSize, int colorMode, int duplexMode,
+            Resolution resolution) {
+        if (mediaSize == null && colorMode == 0 && duplexMode == 0 && resolution == null) {
+            return null;
+        }
+
+        PrintAttributes.Builder builder = new PrintAttributes.Builder();
+
+        if (mediaSize != null) {
+            builder.setMediaSize(mediaSize);
+        }
+
+        if (colorMode != 0) {
+            builder.setColorMode(colorMode);
+        }
+
+        if (duplexMode != 0) {
+            builder.setDuplexMode(duplexMode);
+        }
+
+        if (resolution != null) {
+            builder.setResolution(resolution);
+        }
+
+        return builder.build();
+    }
+
+    /**
+     * Make {@link #PRINTER_NAME} the default printer by adding it to the history of printers by
+     * printing once.
+     *
+     * @param adapter The {@link PrintDocumentAdapter} used
+     * @throws Exception If the printer could not be made default
+     */
+    private void makeDefaultPrinter(PrintDocumentAdapter adapter)
+            throws Exception {
+        // Perform a full print operation on the printer
+        print(adapter);
+        selectPrinter(PRINTER_NAME);
+        clickPrintButton();
+        answerPrintServicesWarning(true);
+        waitForPrinterDiscoverySessionDestroyCallbackCalled();
+
+        // Switch to new activity, which should now use the default printer
+        getActivity().finish();
+        createActivity();
+    }
+
+    /**
+     * Create {@link PrinterDiscoverySessionCallbacks} with a single printer that has the given
+     * capabilities
+     *
+     * @param minMargins The minMargins of the printer
+     * @param mediaSizes The {@link MediaSize media sizes} supported by the printer
+     * @param defaultMediaSize The default {@link MediaSize}
+     * @param colorModes The color modes supported by the printer
+     * @param defaultColorMode The default color mode
+     * @param duplexModes The duplex modes supported by the printer
+     * @param defaultDuplexMode The default duplex mode
+     * @param resolutions The {@link Resolution resolutions} supported by the printer
+     * @param defaultResolution The default {@link Resolution} to use
+     *
+     * @return New {@link PrinterDiscoverySessionCallbacks} with a single printer that has the
+     *         given capabilities
+     */
+    private PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
+            final Margins minMargins, final MediaSize mediaSizes[],
+            final MediaSize defaultMediaSize, final int colorModes[], final int defaultColorMode,
+            final int duplexModes[], final int defaultDuplexMode, final Resolution resolutions[],
+            final Resolution defaultResolution) {
+        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) {
+                StubbablePrinterDiscoverySession session =
+                        ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession();
+
+                if (session.getPrinters().isEmpty()) {
+                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+                    PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME);
+
+                    PrinterCapabilitiesInfo.Builder builder =
+                            new PrinterCapabilitiesInfo.Builder(printerId);
+
+                    builder.setMinMargins(minMargins);
+
+                    int mediaSizesLength = mediaSizes.length;
+                    for (int i = 0; i < mediaSizesLength; i++) {
+                        if (mediaSizes[i].equals(defaultMediaSize)) {
+                            builder.addMediaSize(mediaSizes[i], true);
+                        } else {
+                            builder.addMediaSize(mediaSizes[i], false);
+                        }
+                    }
+
+                    int colorModesMask = 0;
+                    int colorModesLength = colorModes.length;
+                    for (int i = 0; i < colorModesLength; i++) {
+                        colorModesMask |= colorModes[i];
+                    }
+                    builder.setColorModes(colorModesMask, defaultColorMode);
+
+                    int duplexModesMask = 0;
+                    int duplexModeLength = duplexModes.length;
+                    for (int i = 0; i < duplexModeLength; i++) {
+                        duplexModesMask |= duplexModes[i];
+                    }
+                    builder.setDuplexModes(duplexModesMask, defaultDuplexMode);
+
+                    int resolutionsLength = resolutions.length;
+                    for (int i = 0; i < resolutionsLength; i++) {
+                        if (resolutions[i].equals(defaultResolution)) {
+                            builder.addResolution(resolutions[i], true);
+                        } else {
+                            builder.addResolution(resolutions[i], false);
+                        }
+                    }
+
+                    PrinterInfo printer = new PrinterInfo.Builder(printerId, PRINTER_NAME,
+                            PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build();
+                    printers.add(printer);
+
+                    session.addPrinters(printers);
+                }
+                return null;
+            }
+        }, null, null, new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                return null;
+            }
+        }, null, null, new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                // Take a note onDestroy was called.
+                onPrinterDiscoverySessionDestroyCalled();
+                return null;
+            }
+        });
+    }
+
+    /**
+     * Create dummy {@link PrintServiceCallbacks}
+     *
+     * This is needed to as the print framework is trying to talk to any printer even if is not set
+     * up.
+     *
+     * @return Dummy {@link PrintServiceCallbacks}
+     */
+    private PrintServiceCallbacks createDummyMockPrintServiceCallbacks() {
+        return createMockPrintServiceCallbacks(null, null, null);
+    }
+
+    /**
+     * Create a {@link PrintDocumentAdapter} that serves empty pages
+     *
+     * @return A new {@link PrintDocumentAdapter}
+     */
+    private PrintDocumentAdapter createMockPrintDocumentAdapter() {
+        return createMockPrintDocumentAdapter(
+                new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        mLayoutAttributes = (PrintAttributes) invocation.getArguments()[1];
+                        LayoutResultCallback callback =
+                                (LayoutResultCallback) invocation.getArguments()[3];
+                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                                .setPageCount(1)
+                                .build();
+                        callback.onLayoutFinished(info, false);
+                        // Mark layout was called.
+                        onLayoutCalled();
+                        return null;
+                    }
+                }, new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        Object[] args = invocation.getArguments();
+                        PageRange[] pages = (PageRange[]) args[0];
+                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                        WriteResultCallback callback = (WriteResultCallback) args[3];
+                        writeBlankPages(mLayoutAttributes, fd, pages[0].getStart(),
+                                pages[0].getEnd());
+                        fd.close();
+                        callback.onWriteFinished(pages);
+                        // Mark write was called.
+                        onWriteCalled();
+                        return null;
+                    }
+                }, new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        // Mark finish was called.
+                        onFinishCalled();
+                        return null;
+                    }
+                });
+    }
+
+    /**
+     * Set up a single printer with the given capabilities
+     *
+     * @param minMargins The minMargins of the printer
+     * @param mediaSizes The {@link MediaSize media sizes} supported by the printer
+     * @param defaultMediaSize The default {@link MediaSize}
+     * @param colorModes The color modes supported by the printer
+     * @param defaultColorMode The default color mode
+     * @param duplexModes The duplex modes supported by the printer
+     * @param defaultDuplexMode The default duplex mode
+     * @param resolutions The {@link Resolution resolutions} supported by the printer
+     * @param defaultResolution The default {@link Resolution} to use
+     *
+     * @return A {@link PrintDocumentAdapter} that can be used for the new printer
+     */
+    private PrintDocumentAdapter setUpPrinter(Margins minMargins, MediaSize mediaSizes[],
+            MediaSize defaultMediaSize, int colorModes[], int defaultColorMode, int duplexModes[],
+            int defaultDuplexMode, Resolution resolutions[], Resolution defaultResolution) {
+        final PrinterDiscoverySessionCallbacks sessionCallbacks =
+                createMockPrinterDiscoverySessionCallbacks(minMargins, mediaSizes,
+                        defaultMediaSize, colorModes, defaultColorMode, duplexModes,
+                        defaultDuplexMode, resolutions, defaultResolution);
+
+        PrintServiceCallbacks serviceCallbacks = createMockPrintServiceCallbacks(
+                new Answer<PrinterDiscoverySessionCallbacks>() {
+                    @Override
+                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+                        return sessionCallbacks;
+                    }
+                },
+                new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) {
+                        PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                        // We pretend the job is handled immediately.
+                        printJob.complete();
+                        return null;
+                    }
+                }, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(serviceCallbacks);
+
+        // We need to set up the second print service too, otherwise we get a null pointer in the
+        // print framework
+        SecondPrintService.setCallbacks(createDummyMockPrintServiceCallbacks());
+
+        // Create a print adapter that respects the print contract.
+        return createMockPrintDocumentAdapter();
+    }
+
+    /**
+     * Check if a value is in an array.
+     *
+     * To be use instead of Arrays.asList(array).contains(value) for ints.
+     *
+     * @param array The array the value might be in
+     * @param value The value to search for
+     *
+     * @return true iff the value is in the array
+     */
+    private boolean isInArray(final int array[], int value) {
+        int arrayLength = array.length;
+        for (int i = 0; i < arrayLength; i++) {
+            if (array[i] == value) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Flexible base test for all print attribute tests.
+     *
+     * Asserts that the default and suggested attributes are properly honored by the print
+     * framework.
+     *
+     * @param minMargins The minMargins of the printer
+     * @param mediaSizes The {@link MediaSize media sizes} supported by the printer
+     * @param defaultMediaSize The default {@link MediaSize}
+     * @param colorModes The color modes supported by the printer
+     * @param defaultColorMode The default color mode
+     * @param duplexModes The duplex modes supported by the printer
+     * @param defaultDuplexMode The default duplex mode
+     * @param resolutions The {@link Resolution resolutions} supported by the printer
+     * @param defaultResolution The default {@link Resolution} to use
+     * @param suggestedMediaSize The suggested {@link MediaSize} for the print job
+     * @param suggestedColorMode The suggested color mode for the print job
+     * @param suggestedDuplexMode The suggested duplex mode for the print job
+     * @param suggestedResolution The suggested resolution for the print job
+     *
+     * @throws Exception If anything is unexpected
+     */
+    private void baseTest(Margins minMargins, MediaSize mediaSizes[],
+            MediaSize defaultMediaSize, MediaSize suggestedMediaSize, int colorModes[],
+            int defaultColorMode, int suggestedColorMode, int duplexModes[],
+            int defaultDuplexMode, int suggestedDuplexMode, Resolution resolutions[],
+            Resolution defaultResolution, Resolution suggestedResolution) throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+
+        // Set up printer with supported and default attributes
+        PrintDocumentAdapter adapter =
+                setUpPrinter(minMargins, mediaSizes, defaultMediaSize, colorModes, defaultColorMode,
+                        duplexModes, defaultDuplexMode, resolutions, defaultResolution);
+
+        // Make printer default. This is necessary as a different default printer might pre-select
+        // its default attributes and thereby overrides the defaults of the tested printer.
+        makeDefaultPrinter(adapter);
+
+        // Select suggested attributes
+        PrintAttributes suggestedAttributes = createAttributes(suggestedMediaSize,
+                suggestedColorMode, suggestedDuplexMode, suggestedResolution);
+
+        // Start print action and wait for layout, the result is stored in #layoutAttributes,
+        // @see createMockPrintDocumentAdapter
+        print(adapter, suggestedAttributes);
+        waitForWriteAdapterCallback();
+        clickPrintButton();
+        waitForPrinterDiscoverySessionDestroyCallbackCalled();
+
+        // It does not make sense to suggest minMargins, hence the print framework always picks
+        // the one set up for the printer.
+        assertEquals("Min margins not as expected", minMargins, mLayoutAttributes.getMinMargins());
+
+        // Verify that the attributes are honored properly
+        if (suggestedMediaSize != null && Arrays.asList(mediaSizes).contains(suggestedMediaSize)) {
+            assertEquals("Media size not as suggested", suggestedMediaSize,
+                    mLayoutAttributes.getMediaSize());
+        } else {
+            assertEquals("Media size not default", defaultMediaSize,
+                    mLayoutAttributes.getMediaSize());
+        }
+
+        if (suggestedColorMode != 0 && isInArray(colorModes, suggestedColorMode)) {
+            assertEquals("Color mode not as suggested", suggestedColorMode,
+                    mLayoutAttributes.getColorMode());
+        } else {
+            assertEquals("Color mode not default", defaultColorMode,
+                    mLayoutAttributes.getColorMode());
+        }
+
+        if (suggestedDuplexMode != 0 && isInArray(duplexModes, suggestedDuplexMode)) {
+            assertEquals("Duplex mode not as suggested", suggestedDuplexMode,
+                    mLayoutAttributes.getDuplexMode());
+        } else {
+            assertEquals("Duplex mode not default", defaultDuplexMode,
+                    mLayoutAttributes.getDuplexMode());
+        }
+
+        if (suggestedResolution != null
+                && Arrays.asList(resolutions).contains(suggestedResolution)) {
+            assertEquals("Resolution not as suggested", suggestedResolution,
+                    mLayoutAttributes.getResolution());
+        } else {
+            assertEquals("Resolution not default", defaultResolution,
+                    mLayoutAttributes.getResolution());
+        }
+    }
+
+    /**
+     * Test that attributes are as expected if the default attributes match the suggested ones.
+     *
+     * This test sets the default and suggested attributes to the first selection.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testDefaultMatchesSuggested0() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[0],
+                 MEDIA_SIZES,  MEDIA_SIZES[0],  MEDIA_SIZES[0],
+                 COLOR_MODES,  COLOR_MODES[0],  COLOR_MODES[0],
+                 DUPLEX_MODES, DUPLEX_MODES[0], DUPLEX_MODES[0],
+                 RESOLUTIONS,  RESOLUTIONS[0],  RESOLUTIONS[0]);
+    }
+
+    /**
+     * Test that attributes are as expected if the default attributes match the suggested ones.
+     *
+     * This test sets the default and suggested attributes to the second selection.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testDefaultMatchesSuggested1() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[1],
+                 MEDIA_SIZES,  MEDIA_SIZES[1],  MEDIA_SIZES[1],
+                 COLOR_MODES,  COLOR_MODES[1],  COLOR_MODES[1],
+                 DUPLEX_MODES, DUPLEX_MODES[1], DUPLEX_MODES[1],
+                 RESOLUTIONS,  RESOLUTIONS[1],  RESOLUTIONS[1]);
+    }
+
+    /**
+     * Test that attributes are as expected if the default attributes match the suggested ones.
+     *
+     * This test sets the default and suggested attributes to the third selection.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testDefaultMatchesSuggested2() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[2],
+                 MEDIA_SIZES,  MEDIA_SIZES[2],  MEDIA_SIZES[2],
+                 // There are only two color modes, hence pick [1]
+                 COLOR_MODES,  COLOR_MODES[1],  COLOR_MODES[1],
+                 DUPLEX_MODES, DUPLEX_MODES[2], DUPLEX_MODES[2],
+                 RESOLUTIONS,  RESOLUTIONS[2],  RESOLUTIONS[2]);
+    }
+
+    /**
+     * Test that attributes are as expected if the no suggestion is given.
+     *
+     * This test sets the default attributes to the first selection.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testNoSuggestion0() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[0],
+                 MEDIA_SIZES,  MEDIA_SIZES[0],  null,
+                 COLOR_MODES,  COLOR_MODES[0],  0,
+                 DUPLEX_MODES, DUPLEX_MODES[0], 0,
+                 RESOLUTIONS,  RESOLUTIONS[0],  null);
+    }
+
+    /**
+     * Test that attributes are as expected if the no suggestion is given.
+     *
+     * This test sets the default attributes to the second selection.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testNoSuggestion1() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[1],
+                 MEDIA_SIZES,  MEDIA_SIZES[1],  null,
+                 COLOR_MODES,  COLOR_MODES[1],  0,
+                 DUPLEX_MODES, DUPLEX_MODES[1], 0,
+                 RESOLUTIONS,  RESOLUTIONS[1],  null);
+    }
+
+    /**
+     * Test that attributes are as expected if the no suggestion is given.
+     *
+     * This test sets the default attributes to the third selection.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testNoSuggestion2() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[2],
+                 MEDIA_SIZES,  MEDIA_SIZES[2],  null,
+                 // There are only two color modes, hence pick [1]
+                 COLOR_MODES,  COLOR_MODES[1],  0,
+                 DUPLEX_MODES, DUPLEX_MODES[2], 0,
+                 RESOLUTIONS,  RESOLUTIONS[2],  null);
+    }
+
+    /**
+     * Test that attributes are as expected if only the {@link MediaSize} is suggested.
+     *
+     * This test sets the default attributes to the first selection, but the {@link MediaSize} is
+     * suggested to be the second selection.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testMediaSizeSuggestion0() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[0],
+                 MEDIA_SIZES,  MEDIA_SIZES[0],  MEDIA_SIZES[1],
+                 COLOR_MODES,  COLOR_MODES[0],  0,
+                 DUPLEX_MODES, DUPLEX_MODES[0], 0,
+                 RESOLUTIONS,  RESOLUTIONS[0],  null);
+    }
+
+    /**
+     * Test that attributes are as expected if only the {@link MediaSize} is suggested.
+     *
+     * This test sets the default attributes to the second selection, but the {@link MediaSize} is
+     * suggested to be the first selection.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testMediaSizeSuggestion1() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[1],
+                 MEDIA_SIZES,  MEDIA_SIZES[1],  MEDIA_SIZES[0],
+                 COLOR_MODES,  COLOR_MODES[1],  0,
+                 DUPLEX_MODES, DUPLEX_MODES[1], 0,
+                 RESOLUTIONS,  RESOLUTIONS[1],  null);
+    }
+
+    /**
+     * Test that attributes are as expected if only the duplex mode is suggested.
+     *
+     * This test sets the default attributes to the first selection, but the duplex mode is
+     * suggested to be the second selection.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testDuplexModeSuggestion0() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[0],
+                 MEDIA_SIZES,  MEDIA_SIZES[0],  null,
+                 COLOR_MODES,  COLOR_MODES[0],  0,
+                 DUPLEX_MODES, DUPLEX_MODES[0], DUPLEX_MODES[1],
+                 RESOLUTIONS,  RESOLUTIONS[0],  null);
+    }
+
+    /**
+     * Test that attributes are as expected if only the duplex mode is suggested.
+     *
+     * This test sets the default attributes to the second selection, but the duplex mode is
+     * suggested to be the first selection.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testDuplexModeSuggestion1() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[1],
+                 MEDIA_SIZES,  MEDIA_SIZES[1],  null,
+                 COLOR_MODES,  COLOR_MODES[1],  0,
+                 DUPLEX_MODES, DUPLEX_MODES[1], DUPLEX_MODES[0],
+                 RESOLUTIONS,  RESOLUTIONS[1],  null);
+    }
+
+    /**
+     * Test that attributes are as expected if all attributes are suggested and different from the
+     * default attributes.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testSuggestedDifferentFromDefault() throws Exception {
+        //       available     default          suggestion
+        baseTest(              MIN_MARGINS[0],
+                 MEDIA_SIZES,  MEDIA_SIZES[0],  MEDIA_SIZES[1],
+                 COLOR_MODES,  COLOR_MODES[0],  COLOR_MODES[1],
+                 DUPLEX_MODES, DUPLEX_MODES[0], DUPLEX_MODES[1],
+                 RESOLUTIONS,  RESOLUTIONS[0],  RESOLUTIONS[1]);
+    }
+
+    /**
+     * Test that attributes are as expected if all attributes are suggested but all of them are not
+     * supported by the printer.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testIllegalSuggested() throws Exception {
+        //       available                               default          suggestion
+        baseTest(                                        MIN_MARGINS[0],
+                 Arrays.copyOfRange(MEDIA_SIZES, 0, 1),  MEDIA_SIZES[0],  MEDIA_SIZES[1],
+                 Arrays.copyOfRange(COLOR_MODES, 0, 1),  COLOR_MODES[0],  COLOR_MODES[1],
+                 Arrays.copyOfRange(DUPLEX_MODES, 0, 1), DUPLEX_MODES[0], DUPLEX_MODES[1],
+                 Arrays.copyOfRange(RESOLUTIONS, 0, 1),  RESOLUTIONS[0],  RESOLUTIONS[1]);
+    }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
index 9f1e3a5..24eb951 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
@@ -122,6 +122,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -142,6 +145,7 @@
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -256,6 +260,7 @@
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -363,6 +368,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for a finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -383,6 +391,7 @@
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -552,6 +561,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for a finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -572,6 +584,7 @@
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -613,6 +626,7 @@
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(new Margins(200, 200, 200, 200))
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, fourthOldAttributes, fourthNewAttributes, true);
 
@@ -699,6 +713,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for a finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -718,6 +735,7 @@
                 .setMediaSize(MediaSize.NA_LETTER)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -823,6 +841,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for a finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -842,6 +863,7 @@
                 .setMediaSize(MediaSize.NA_LETTER)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -932,6 +954,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for a finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -951,6 +976,7 @@
                 .setMediaSize(MediaSize.NA_LETTER)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -1058,6 +1084,7 @@
                 .setMediaSize(MediaSize.NA_LETTER)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -1152,6 +1179,7 @@
                 .setMediaSize(MediaSize.NA_LETTER)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -1224,6 +1252,7 @@
                 .setMediaSize(MediaSize.NA_LETTER)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -1306,6 +1335,7 @@
                 .setMediaSize(MediaSize.NA_LETTER)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -1350,7 +1380,6 @@
                 Object[] args = invocation.getArguments();
                 ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
                 WriteResultCallback callback = (WriteResultCallback) args[3];
-                PageRange[] pages = (PageRange[]) args[0];
                 writeBlankPages(printAttributes[0], fd, Integer.MAX_VALUE, Integer.MAX_VALUE);
                 fd.close();
                 // Write wrong pages.
@@ -1398,6 +1427,7 @@
                 .setMediaSize(MediaSize.NA_LETTER)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -1469,6 +1499,7 @@
                 .setMediaSize(MediaSize.NA_LETTER)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -1548,6 +1579,7 @@
                 .setMediaSize(MediaSize.NA_LETTER)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
                 .build();
         verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
 
@@ -1636,7 +1668,7 @@
                 }
                 return null;
             }
-        }, null, null, null, null, new Answer<Void>() {
+        }, null, null, null, null, null, new Answer<Void>() {
                 @Override
                 public Void answer(InvocationOnMock invocation) throws Throwable {
                     // Take a note onDestroy was called.
diff --git a/tests/tests/print/src/android/print/cts/PrintServicesTest.java b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
new file mode 100644
index 0000000..c8fc265
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2015 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.print.cts;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.print.PrintDocumentInfo;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.print.cts.services.FirstPrintService;
+import android.print.cts.services.PrintServiceCallbacks;
+import android.print.cts.services.PrinterDiscoverySessionCallbacks;
+import android.print.cts.services.SecondPrintService;
+import android.print.cts.services.StubbablePrinterDiscoverySession;
+import android.printservice.CustomPrinterIconCallback;
+import android.printservice.PrintJob;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiSelector;
+
+import junit.framework.AssertionFailedError;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Test the interface from a print service to the print manager
+ */
+public class PrintServicesTest extends BasePrintTest {
+    private static final String PRINTER_NAME = "Test printer";
+    private static final int NUM_PAGES = 2;
+
+    /** The print job processed in the test */
+    private static PrintJob mPrintJob;
+
+    /** The current progress of #mPrintJob once read from the system */
+    private static float mPrintProgress;
+
+    /** Printer under test */
+    private static PrinterInfo mPrinter;
+
+    /** The printer discovery session used in this test */
+    private static StubbablePrinterDiscoverySession mDiscoverySession;
+
+    /** The current status of #mPrintJob once read from the system */
+    private static CharSequence mPrintStatus;
+
+    /** The custom printer icon to use */
+    private Icon mIcon;
+
+    /**
+     * Create a mock {@link PrintDocumentAdapter} that provides {@link #NUM_PAGES} empty pages.
+     *
+     * @return The mock adapter
+     */
+    private PrintDocumentAdapter createMockPrintDocumentAdapter() {
+        final PrintAttributes[] printAttributes = new PrintAttributes[1];
+
+        return createMockPrintDocumentAdapter(
+                new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                        LayoutResultCallback callback = (LayoutResultCallback) invocation
+                                .getArguments()[3];
+
+                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                                .setPageCount(NUM_PAGES)
+                                .build();
+
+                        callback.onLayoutFinished(info, false);
+
+                        // Mark layout was called.
+                        onLayoutCalled();
+                        return null;
+                    }
+                }, new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        Object[] args = invocation.getArguments();
+                        PageRange[] pages = (PageRange[]) args[0];
+                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                        WriteResultCallback callback = (WriteResultCallback) args[3];
+
+                        writeBlankPages(printAttributes[0], fd, pages[0].getStart(),
+                                pages[0].getEnd());
+                        fd.close();
+                        callback.onWriteFinished(pages);
+
+                        // Mark write was called.
+                        onWriteCalled();
+                        return null;
+                    }
+                }, new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        // Mark finish was called.
+                        onFinishCalled();
+                        return null;
+                    }
+                });
+    }
+
+    /**
+     * Create a mock {@link PrinterDiscoverySessionCallbacks} that discovers a single printer with
+     * minimal capabilities.
+     *
+     * @return The mock session callbacks
+     */
+    private PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() {
+        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) {
+                // Get the session.
+                mDiscoverySession = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
+                        .getSession();
+
+                if (mDiscoverySession.getPrinters().isEmpty()) {
+                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+
+                    // Add the printer.
+                    PrinterId printerId = mDiscoverySession.getService()
+                            .generatePrinterId(PRINTER_NAME);
+
+                    PrinterCapabilitiesInfo capabilities = new PrinterCapabilitiesInfo.Builder(
+                            printerId)
+                                    .setMinMargins(new Margins(200, 200, 200, 200))
+                                    .addMediaSize(MediaSize.ISO_A4, true)
+                                    .addResolution(new Resolution("300x300", "300x300", 300, 300),
+                                            true)
+                                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                            PrintAttributes.COLOR_MODE_COLOR)
+                                    .build();
+
+                    Intent infoIntent = new Intent(getActivity(), Activity.class);
+                    PendingIntent infoPendingIntent = PendingIntent.getActivity(getActivity(), 0,
+                            infoIntent, PendingIntent.FLAG_IMMUTABLE);
+
+                    mPrinter = new PrinterInfo.Builder(printerId, PRINTER_NAME,
+                            PrinterInfo.STATUS_IDLE)
+                                    .setCapabilities(capabilities)
+                                    .setDescription("Minimal capabilities")
+                                    .setInfoIntent(infoPendingIntent)
+                                    .build();
+                    printers.add(mPrinter);
+
+                    mDiscoverySession.addPrinters(printers);
+                }
+                return null;
+            }
+        }, null, null, new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                return null;
+            }
+        }, new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                CustomPrinterIconCallback callback = (CustomPrinterIconCallback) invocation
+                        .getArguments()[1];
+
+                if (mIcon != null) {
+                    callback.onCustomPrinterIconLoaded(mIcon);
+                }
+                return null;
+            }
+        }, null, new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                // Take a note onDestroy was called.
+                onPrinterDiscoverySessionDestroyCalled();
+                return null;
+            }
+        });
+    }
+
+    /**
+     * Get the current progress of #mPrintJob
+     *
+     * @return The current progress
+     * @throws InterruptedException If the thread was interrupted while setting the progress
+     */
+    private float getProgress() throws InterruptedException {
+        final PrintServicesTest synchronizer = PrintServicesTest.this;
+
+        synchronized (synchronizer) {
+            Runnable getter = new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (synchronizer) {
+                        mPrintProgress = mPrintJob.getInfo().getProgress();
+
+                        synchronizer.notify();
+                    }
+                }
+            };
+
+            (new Handler(Looper.getMainLooper())).post(getter);
+
+            synchronizer.wait();
+        }
+
+        return mPrintProgress;
+    }
+
+    /**
+     * Get the current status of #mPrintJob
+     *
+     * @return The current status
+     * @throws InterruptedException If the thread was interrupted while getting the status
+     */
+    private CharSequence getStatus() throws InterruptedException {
+        final PrintServicesTest synchronizer = PrintServicesTest.this;
+
+        synchronized (synchronizer) {
+            Runnable getter = new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (synchronizer) {
+                        mPrintStatus = mPrintJob.getInfo().getStatus();
+
+                        synchronizer.notify();
+                    }
+                }
+            };
+
+            (new Handler(Looper.getMainLooper())).post(getter);
+
+            synchronizer.wait();
+        }
+
+        return mPrintStatus;
+    }
+
+    /**
+     * Check if a print progress is correct.
+     *
+     * @param desiredProgress The expected @{link PrintProgresses}
+     * @throws Exception If anything goes wrong or this takes more than 5 seconds
+     */
+    private void checkNotification(float desiredProgress,
+            CharSequence desiredStatus) throws Exception {
+        final long TIMEOUT = 5000;
+        final Date start = new Date();
+
+        while ((new Date()).getTime() - start.getTime() < TIMEOUT) {
+            if (desiredProgress == getProgress()
+                    && desiredStatus.toString().equals(getStatus().toString())) {
+                return;
+            }
+
+            Thread.sleep(200);
+        }
+
+        throw new TimeoutException("Progress or status not updated in " + TIMEOUT + " ms");
+    }
+
+    /**
+     * Set a new progress and status for #mPrintJob
+     *
+     * @param progress The new progress to set
+     * @param status The new status to set
+     * @throws InterruptedException If the thread was interrupted while setting
+     */
+    private void setProgressAndStatus(final float progress, final CharSequence status)
+            throws InterruptedException {
+        final PrintServicesTest synchronizer = PrintServicesTest.this;
+
+        synchronized (synchronizer) {
+            Runnable completer = new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (synchronizer) {
+                        mPrintJob.setProgress(progress);
+                        mPrintJob.setStatus(status);
+
+                        synchronizer.notify();
+                    }
+                }
+            };
+
+            (new Handler(Looper.getMainLooper())).post(completer);
+
+            synchronizer.wait();
+        }
+    }
+
+    /**
+     * Progress print job and check the print job state.
+     *
+     * @param progress How much to progress
+     * @param status The status to set
+     * @throws Exception If anything goes wrong.
+     */
+    private void progress(float progress, CharSequence status) throws Exception {
+        setProgressAndStatus(progress, status);
+
+        // Check that progress of job is correct
+        checkNotification(progress, status);
+    }
+
+    /**
+     * Create mock service callback for a session.
+     *
+     * @param sessionCallbacks The callbacks of the sessopm
+     */
+    private PrintServiceCallbacks createFirstMockPrinterServiceCallbacks(
+            final PrinterDiscoverySessionCallbacks sessionCallbacks) {
+        return createMockPrintServiceCallbacks(
+                new Answer<PrinterDiscoverySessionCallbacks>() {
+                    @Override
+                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+                        return sessionCallbacks;
+                    }
+                },
+                new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) {
+                        mPrintJob = (PrintJob) invocation.getArguments()[0];
+                        mPrintJob.start();
+                        onPrintJobQueuedCalled();
+
+                        return null;
+                    }
+                }, null);
+    }
+
+    /**
+     * Test that the progress and status is propagated correctly.
+     *
+     * @throws Exception If anything is unexpected.
+     */
+    public void testProgress()
+            throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+        // Create the session callbacks that we will be checking.
+        PrinterDiscoverySessionCallbacks sessionCallbacks
+                = createFirstMockPrinterDiscoverySessionCallbacks();
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
+                sessionCallbacks);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(serviceCallbacks);
+
+        // We don't use the second service, but we have to still configure it
+        SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+        // Create a print adapter that respects the print contract.
+        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+
+        // Start printing.
+        print(adapter);
+
+        // Wait for write of the first page.
+        waitForWriteAdapterCallback();
+
+        // Select the printer.
+        selectPrinter(PRINTER_NAME);
+
+        // Click the print button.
+        clickPrintButton();
+
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
+        // Wait until the print job is queued and #mPrintJob is set
+        waitForServiceOnPrintJobQueuedCallbackCalled();
+
+        // Progress print job and check for appropriate notifications
+        progress(0, "printed 0");
+        progress(0.5f, "printed 50");
+        progress(1, "printed 100");
+
+        // Call complete from the main thread
+        Handler handler = new Handler(Looper.getMainLooper());
+
+        Runnable completer = new Runnable() {
+            @Override
+            public void run() {
+                mPrintJob.complete();
+            }
+        };
+
+        handler.post(completer);
+
+        // Wait for all print jobs to be handled after which the session destroyed.
+        waitForPrinterDiscoverySessionDestroyCallbackCalled();
+    }
+
+    /**
+     * Render a {@link Drawable} into a {@link Bitmap}.
+     *
+     * @param d the drawable to be rendered
+     * @return the rendered bitmap
+     */
+    private static Bitmap renderDrawable(Drawable d) {
+        Bitmap bitmap = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(),
+                Bitmap.Config.ARGB_8888);
+
+        Canvas canvas = new Canvas(bitmap);
+        d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        d.draw(canvas);
+
+        return bitmap;
+    }
+
+    /**
+     * Update the printer
+     *
+     * @param printer the new printer to use
+     * @throws InterruptedException If we were interrupted while the printer was updated.
+     */
+    private void updatePrinter(final PrinterInfo printer)
+            throws InterruptedException {
+        final PrintServicesTest synchronizer = PrintServicesTest.this;
+
+        synchronized (synchronizer) {
+            Runnable updated = new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (synchronizer) {
+                        ArrayList<PrinterInfo> printers = new ArrayList<>(1);
+                        printers.add(printer);
+                        mDiscoverySession.addPrinters(printers);
+
+                        synchronizer.notifyAll();
+                    }
+                }
+            };
+
+            (new Handler(Looper.getMainLooper())).post(updated);
+
+            synchronizer.wait();
+        }
+
+        // Update local copy of printer
+        mPrinter = printer;
+    }
+
+    /**
+     * Assert is the printer icon does not match the bitmap. As the icon update might take some time
+     * we try up to 5 seconds.
+     *
+     * @param bitmap The bitmap to match
+     */
+    private void assertThatIconIs(Bitmap bitmap) {
+        final long TIMEOUT = 5000;
+
+        final long startMillis = SystemClock.uptimeMillis();
+        while (true) {
+            try {
+                if (bitmap.sameAs(renderDrawable(mPrinter.loadIcon(getActivity())))) {
+                    return;
+                }
+                final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
+                final long waitMillis = TIMEOUT - elapsedMillis;
+                if (waitMillis <= 0) {
+                    throw new AssertionFailedError("Icon does not match bitmap");
+                }
+
+                // We do not get notified about the icon update, hence wait and try again.
+                Thread.sleep(1000);
+            } catch (InterruptedException ie) {
+               /* ignore */
+            }
+        }
+    }
+
+    /**
+     * Test that the icon get be updated.
+     *
+     * @throws Exception If anything is unexpected.
+     */
+    public void testUpdateIcon()
+            throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+        // Create the session callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks sessionCallbacks
+                = createFirstMockPrinterDiscoverySessionCallbacks();
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
+                sessionCallbacks);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(serviceCallbacks);
+
+        // We don't use the second service, but we have to still configure it
+        SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+        // Create a print adapter that respects the print contract.
+        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+
+        // Start printing.
+        print(adapter);
+
+        // Open printer selection dropdown list to display icon on screen
+        UiObject destinationSpinner = UiDevice.getInstance(getInstrumentation())
+                .findObject(new UiSelector().resourceId(
+                        "com.android.printspooler:id/destination_spinner"));
+        destinationSpinner.click();
+
+        // Get the print service's icon
+        PackageManager packageManager = getActivity().getPackageManager();
+        PackageInfo packageInfo = packageManager.getPackageInfo(
+                new ComponentName(getActivity(), FirstPrintService.class).getPackageName(), 0);
+        ApplicationInfo appInfo = packageInfo.applicationInfo;
+        Drawable printServiceIcon = appInfo.loadIcon(packageManager);
+
+        assertThatIconIs(renderDrawable(printServiceIcon));
+
+        // Update icon to resource
+        updatePrinter((new PrinterInfo.Builder(mPrinter)).setIconResourceId(R.drawable.red_printer)
+                .build());
+
+        assertThatIconIs(renderDrawable(getActivity().getDrawable(R.drawable.red_printer)));
+
+        // Update icon to bitmap
+        Bitmap bm = BitmapFactory.decodeResource(getActivity().getResources(),
+                R.raw.yellow_printer);
+        // Icon will be picked up from the discovery session once setHasCustomPrinterIcon is set
+        mIcon = Icon.createWithBitmap(bm);
+        updatePrinter((new PrinterInfo.Builder(mPrinter)).setHasCustomPrinterIcon().build());
+
+        assertThatIconIs(renderDrawable(mIcon.loadDrawable(getActivity())));
+    }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
index 7ea09e5..a198790 100644
--- a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
@@ -39,7 +39,6 @@
 import android.printservice.PrintJob;
 import android.printservice.PrinterDiscoverySession;
 
-import junit.framework.AssertionFailedError;
 import org.mockito.InOrder;
 import org.mockito.exceptions.verification.VerificationInOrderFailure;
 import org.mockito.invocation.InvocationOnMock;
@@ -123,6 +122,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for all print jobs to be handled after which the session destroyed.
         waitForPrinterDiscoverySessionDestroyCallbackCalled();
 
@@ -157,6 +159,93 @@
         inOrder.verify(firstSessionCallbacks).onDestroy();
     }
 
+    public void testCancelPrintServicesAlertDialog() throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+        // Create the session callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+                createFirstMockPrinterDiscoverySessionCallbacks();
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+                new Answer<PrinterDiscoverySessionCallbacks>() {
+                    @Override
+                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+                        return firstSessionCallbacks;
+                    }
+                },
+                new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) {
+                        PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                        // We pretend the job is handled immediately.
+                        printJob.complete();
+                        return null;
+                    }
+                }, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(firstServiceCallbacks);
+
+        // Create a print adapter that respects the print contract.
+        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+
+        // Start printing.
+        print(adapter);
+
+        // Wait for write of the first page.
+        waitForWriteAdapterCallback();
+
+        // Select the first printer.
+        selectPrinter(FIRST_PRINTER_NAME);
+
+        // While the printer discovery session is still alive store the
+        // ids of printers as we want to make some assertions about them
+        // but only the print service can create printer ids which means
+        // that we need to get the created ones.
+        PrinterId firstPrinterId = getAddedPrinterIdForLocalId(firstSessionCallbacks,
+                FIRST_PRINTER_LOCAL_ID);
+        assertNotNull("Coundn't find printer:" + FIRST_PRINTER_LOCAL_ID, firstPrinterId);
+
+        // Click the print button.
+        clickPrintButton();
+
+        // Cancel the dialog for the print service cloud warning
+        answerPrintServicesWarning(false);
+
+        // Click the print button again.
+        clickPrintButton();
+
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
+        // Wait for all print jobs to be handled after which the session destroyed.
+        waitForPrinterDiscoverySessionDestroyCallbackCalled();
+
+        // Verify the expected calls.
+        InOrder inOrder = inOrder(firstSessionCallbacks);
+
+        // We start discovery as the print dialog was up.
+        List<PrinterId> emptyPrinterIdList = Collections.emptyList();
+        inOrder.verify(firstSessionCallbacks).onStartPrinterDiscovery(
+                emptyPrinterIdList);
+
+        // We selected the first printer and now it should be tracked.
+        inOrder.verify(firstSessionCallbacks).onStartPrinterStateTracking(
+                firstPrinterId);
+
+        // We selected the second printer so the first should not be tracked.
+        inOrder.verify(firstSessionCallbacks).onStopPrinterStateTracking(
+                firstPrinterId);
+
+        // ... next we stop printer discovery...
+        inOrder.verify(firstSessionCallbacks).onStopPrinterDiscovery();
+
+        // ... last the session is destroyed.
+        inOrder.verify(firstSessionCallbacks).onDestroy();
+    }
+
     public void testStartPrinterDiscoveryWithHistoricalPrinters() throws Exception {
         if (!supportsPrinting()) {
             return;
@@ -213,6 +302,9 @@
         // Click the print button.
         clickPrintButton();
 
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
         // Wait for the print to complete.
         waitForAdapterFinishCallbackCalled();
 
@@ -385,7 +477,7 @@
 
                 return null;
             }
-        }, null, new Answer<Void>() {
+        }, null, null, new Answer<Void>() {
             @Override
             public Void answer(InvocationOnMock invocation) throws Throwable {
                 // Take a note onDestroy was called.
diff --git a/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java b/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java
index 6b2c3a9..2e0e729 100644
--- a/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java
+++ b/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java
@@ -17,6 +17,7 @@
 package android.print.cts.services;
 
 import android.print.PrinterId;
+import android.printservice.CustomPrinterIconCallback;
 
 import java.util.List;
 
@@ -40,6 +41,9 @@
 
     public abstract void onStartPrinterStateTracking(PrinterId printerId);
 
+    public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
+            CustomPrinterIconCallback callback);
+
     public abstract void onStopPrinterStateTracking(PrinterId printerId);
 
     public abstract void onDestroy();
diff --git a/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java b/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
index fdc2713..4c2d8b8 100644
--- a/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
+++ b/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
@@ -17,6 +17,7 @@
 package android.print.cts.services;
 
 import android.print.PrinterId;
+import android.printservice.CustomPrinterIconCallback;
 import android.printservice.PrintService;
 import android.printservice.PrinterDiscoverySession;
 
@@ -68,6 +69,14 @@
     }
 
     @Override
+    public void onRequestCustomPrinterIcon(PrinterId printerId,
+            CustomPrinterIconCallback callback) {
+        if (mCallbacks != null) {
+            mCallbacks.onRequestCustomPrinterIcon(printerId, callback);
+        }
+    }
+
+    @Override
     public void onStopPrinterStateTracking(PrinterId printerId) {
         if (mCallbacks != null) {
             mCallbacks.onStopPrinterStateTracking(printerId);
diff --git a/tests/tests/provider/Android.mk b/tests/tests/provider/Android.mk
index 58a7516..d9642d3b 100644
--- a/tests/tests/provider/Android.mk
+++ b/tests/tests/provider/Android.mk
@@ -25,6 +25,11 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
diff --git a/tests/tests/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index ed180f6..b4836d0 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.cts.provider">
+          package="android.provider.cts">
 
     <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
 
@@ -50,7 +50,7 @@
         </activity>
 
         <service android:name="android.provider.cts.contacts.account.MockAccountService"
-                 process="com.android.cts.provider"
+                 process="android.provider.cts"
                  android:exported="true">
             <intent-filter>
                 <action android:name="android.accounts.AccountAuthenticator"/>
@@ -72,14 +72,14 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.provider"
+                     android:targetPackage="android.provider.cts"
                      android:label="CTS tests of android.provider">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
 
     <instrumentation android:name="android.provider.cts.CalendarTest$CalendarEmmaTestRunner"
-                     android:targetPackage="com.android.cts.provider"
+                     android:targetPackage="android.provider.cts"
                      android:label="Augmented CTS tests of Calendar provider"/>
 
 </manifest>
diff --git a/tests/tests/provider/AndroidTest.xml b/tests/tests/provider/AndroidTest.xml
index ae603a3..4c87f9c 100644
--- a/tests/tests/provider/AndroidTest.xml
+++ b/tests/tests/provider/AndroidTest.xml
@@ -1,22 +1,25 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<configuration description="Test module config for provider">
-    <include name="common-config" />
-    <option name="cts-apk-installer:test-file-name" value="CtsProviderTestCases.apk" />
-    <option name="run-command:run-command"
-            value="ime enable com.android.cts.provider/.MockInputMethodService" />
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Provider test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsProviderTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.provider.cts" />
+        <option name="runtime-hint" value="7m19s" />
+    </test>
 </configuration>
\ No newline at end of file
diff --git a/tests/tests/provider/OldAndroidTest.xml b/tests/tests/provider/OldAndroidTest.xml
new file mode 100644
index 0000000..bd22d8f
--- /dev/null
+++ b/tests/tests/provider/OldAndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<configuration description="Test module config for provider">
+    <include name="common-config" />
+    <option name="run-command:run-command"
+            value="ime enable android.provider.cts/.MockInputMethodService" />
+</configuration>
diff --git a/tests/tests/provider/src/android/provider/cts/CalendarTest.java b/tests/tests/provider/src/android/provider/cts/CalendarTest.java
index c9e2213..df31a19 100644
--- a/tests/tests/provider/src/android/provider/cts/CalendarTest.java
+++ b/tests/tests/provider/src/android/provider/cts/CalendarTest.java
@@ -3279,7 +3279,7 @@
     @MediumTest
     public void testMutatorSetCorrectly() {
         String account = "ec_account";
-        String packageName = "com.android.cts.provider";
+        String packageName = "android.provider.cts";
         int seed = 0;
 
         // Clean up just in case
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_CommonDataKinds_OrganizationTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_CommonDataKinds_OrganizationTest.java
index 2de3b05..fa83d4f 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_CommonDataKinds_OrganizationTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_CommonDataKinds_OrganizationTest.java
@@ -16,9 +16,12 @@
 
 package android.provider.cts;
 
+import junit.framework.Assert;
+
 import android.content.res.Resources;
 import android.provider.ContactsContract.CommonDataKinds.Im;
 import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.Data;
 import android.test.AndroidTestCase;
 
 public class ContactsContract_CommonDataKinds_OrganizationTest extends AndroidTestCase {
@@ -51,4 +54,10 @@
         assertTrue(res != 0);
         assertEquals(label, Organization.getTypeLabel(mResources, Im.TYPE_CUSTOM, label));
     }
+
+    public void testPhoneticNameStyleColumnName() throws Exception {
+        // Make sure the column name is data10 and not phonetic_name_style
+        // from the parent class.
+        assertEquals(Data.DATA10, Organization.PHONETIC_NAME_STYLE);
+    }
 }
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_StatusUpdatesTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_StatusUpdatesTest.java
index 2f3cdeb..375d7b2 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_StatusUpdatesTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_StatusUpdatesTest.java
@@ -33,7 +33,7 @@
 
 public class ContactsContract_StatusUpdatesTest extends AndroidTestCase {
 
-    private static final String ACCOUNT_TYPE = "com.android.cts.provider";
+    private static final String ACCOUNT_TYPE = "android.provider.cts";
     private static final String ACCOUNT_NAME = "ContactsContract_StatusUpdatesTest";
 
     private ContentResolver mResolver;
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_StructuredPhoneticName.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_StructuredPhoneticName.java
index 4efd9a7..42bc6d2 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_StructuredPhoneticName.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_StructuredPhoneticName.java
@@ -24,6 +24,7 @@
 import android.provider.ContactsContract.AggregationExceptions;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.DisplayNameSources;
 import android.provider.ContactsContract.RawContacts;
 import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
@@ -72,6 +73,12 @@
                 DisplayNameSources.STRUCTURED_PHONETIC_NAME);
     }
 
+    public void testPhoneticNameStyleColumnName() throws Exception {
+        // Make sure the column name is data11 and not phonetic_name_style
+        // from the parent class.
+        assertEquals(Data.DATA11, StructuredName.PHONETIC_NAME_STYLE);
+    }
+
     public void testPhoneticStructuredName_phoneticPriority1() throws Exception {
         // Setup: one raw contact has a complex phonetic name and the other a simple given name
         TestRawContact rawContact1 = mBuilder.newRawContact()
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsTest.java
index 4d1cb86..ff785fd 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsTest.java
@@ -220,12 +220,12 @@
         try {
             Context context = getInstrumentation().getTargetContext();
             InputStream inputStream = context.getResources().openRawResource(
-                    com.android.cts.provider.R.drawable.testimage);
+                    android.provider.cts.R.drawable.testimage);
             int size = inputStream.available();
             byte[] data =  new byte[size];
             inputStream.read(data);
             BitmapDrawable sourceDrawable = (BitmapDrawable) context.getResources().getDrawable(
-                    com.android.cts.provider.R.drawable.testimage);
+                    android.provider.cts.R.drawable.testimage);
             // Test: insert
             ContentValues value = new ContentValues();
             value.put(Photos.PERSON_ID, 1);
diff --git a/tests/tests/provider/src/android/provider/cts/Contacts_PeopleTest.java b/tests/tests/provider/src/android/provider/cts/Contacts_PeopleTest.java
index 6b5de96..d887aa7 100644
--- a/tests/tests/provider/src/android/provider/cts/Contacts_PeopleTest.java
+++ b/tests/tests/provider/src/android/provider/cts/Contacts_PeopleTest.java
@@ -257,7 +257,7 @@
         Context context = getInstrumentation().getTargetContext();
         try {
             InputStream inputStream = context.getResources().openRawResource(
-                    com.android.cts.provider.R.drawable.testimage);
+                    android.provider.cts.R.drawable.testimage);
             int size = inputStream.available();
             byte[] data =  new byte[size];
             inputStream.read(data);
@@ -275,12 +275,12 @@
             assertNull(photoStream);
 
             bitmap = People.loadContactPhoto(context, mPeopleRowsAdded.get(0),
-                    com.android.cts.provider.R.drawable.size_48x48, null);
+                    android.provider.cts.R.drawable.size_48x48, null);
             assertEquals(96, bitmap.getWidth());
             assertEquals(64, bitmap.getHeight());
 
             bitmap = People.loadContactPhoto(context, null,
-                    com.android.cts.provider.R.drawable.size_48x48, null);
+                    android.provider.cts.R.drawable.size_48x48, null);
             assertNotNull(bitmap);
         } catch (IOException e) {
             fail("Unexpected IOException");
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreAudioTestHelper.java b/tests/tests/provider/src/android/provider/cts/MediaStoreAudioTestHelper.java
index c9eb506..56d74f3 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStoreAudioTestHelper.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreAudioTestHelper.java
@@ -107,7 +107,7 @@
         public static final String DISPLAY_NAME = "Jam -Michael Jackson";
 
         public static final String INTERNAL_DATA =
-            "/data/data/com.android.cts.provider/files/Jam.mp3";
+            "/data/data/android.provider.cts/files/Jam.mp3";
 
         public static final String FILE_NAME = "Jam.mp3";
 
@@ -190,7 +190,7 @@
             Environment.getExternalStorageDirectory().getPath() + "/" + FILE_NAME;
 
         public static final String INTERNAL_DATA =
-            "/data/data/com.android.cts.provider/files/Jam_live.mp3";
+            "/data/data/android.provider.cts/files/Jam_live.mp3";
 
 
 
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java
index 84da62a..3bd81ce 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java
@@ -16,7 +16,7 @@
 
 package android.provider.cts;
 
-import com.android.cts.provider.R;
+import android.provider.cts.R;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_PlaylistsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_PlaylistsTest.java
index 8dcb1a8..463dfcb 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_PlaylistsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_PlaylistsTest.java
@@ -112,7 +112,7 @@
     public void testStoreAudioPlaylistsInternal() {
         ContentValues values = new ContentValues();
         values.put(Playlists.NAME, "My favourites");
-        values.put(Playlists.DATA, "/data/data/com.android.cts.provider/files/my_favorites.pl");
+        values.put(Playlists.DATA, "/data/data/android.provider.cts/files/my_favorites.pl");
         long dateAdded = System.currentTimeMillis();
         values.put(Playlists.DATE_ADDED, dateAdded);
         long dateModified = System.currentTimeMillis();
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Playlists_MembersTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Playlists_MembersTest.java
index 58c1cdf..cc69942 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Playlists_MembersTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Playlists_MembersTest.java
@@ -454,7 +454,7 @@
     public void testStoreAudioPlaylistsMembersInternal() {
         ContentValues values = new ContentValues();
         values.put(Playlists.NAME, "My favourites");
-        values.put(Playlists.DATA, "/data/data/com.android.cts.provider/files/my_favorites.pl");
+        values.put(Playlists.DATA, "/data/data/android.provider.cts/files/my_favorites.pl");
         long dateAdded = System.currentTimeMillis();
         values.put(Playlists.DATE_ADDED, dateAdded);
         long dateModified = System.currentTimeMillis();
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
index 8fc5df1..3ccc61b 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
@@ -16,7 +16,7 @@
 
 package android.provider.cts;
 
-import com.android.cts.provider.R;
+import android.provider.cts.R;
 
 import android.content.ContentResolver;
 import android.content.ContentUris;
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
index 7469f8e..589b5cd 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
@@ -16,7 +16,7 @@
 
 package android.provider.cts;
 
-import com.android.cts.provider.R;
+import android.provider.cts.R;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
index ec9db8b..db3db6b 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
@@ -16,7 +16,7 @@
 
 package android.provider.cts;
 
-import com.android.cts.provider.R;
+import android.provider.cts.R;
 
 import android.content.ContentResolver;
 import android.content.ContentUris;
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java
index 89de9c6..e50f18a 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java
@@ -16,7 +16,7 @@
 
 package android.provider.cts;
 
-import com.android.cts.provider.R;
+import android.provider.cts.R;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
index f84b75c..5ec765c 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
@@ -17,7 +17,7 @@
 package android.provider.cts;
 
 
-import com.android.cts.provider.R;
+import android.provider.cts.R;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
index 974eeb71..9c41274 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
@@ -16,7 +16,7 @@
 
 package android.provider.cts;
 
-import com.android.cts.provider.R;
+import android.provider.cts.R;
 
 import android.content.ContentResolver;
 import android.content.ContentUris;
diff --git a/tests/tests/provider/src/android/provider/cts/PhotoUtil.java b/tests/tests/provider/src/android/provider/cts/PhotoUtil.java
index ec4fdef..4debd8f 100644
--- a/tests/tests/provider/src/android/provider/cts/PhotoUtil.java
+++ b/tests/tests/provider/src/android/provider/cts/PhotoUtil.java
@@ -16,7 +16,7 @@
 
 package android.provider.cts;
 
-import com.android.cts.provider.R;
+import android.provider.cts.R;
 
 import android.content.Context;
 import android.cts.util.FileUtils;
diff --git a/tests/tests/renderscript/Android.mk b/tests/tests/renderscript/Android.mk
index 5266e34..9f196ca 100644
--- a/tests/tests/renderscript/Android.mk
+++ b/tests/tests/renderscript/Android.mk
@@ -37,5 +37,8 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/renderscript/AndroidManifest.xml b/tests/tests/renderscript/AndroidManifest.xml
index 6e67f9e..c6b3891 100644
--- a/tests/tests/renderscript/AndroidManifest.xml
+++ b/tests/tests/renderscript/AndroidManifest.xml
@@ -19,7 +19,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.renderscript">
+    package="android.renderscript.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -30,7 +30,7 @@
 
     <!-- This is a self-instrumenting test package. -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.renderscript"
+                     android:targetPackage="android.renderscript.cts"
                      android:label="CTS tests of Renderscript component">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/renderscript/AndroidTest.xml b/tests/tests/renderscript/AndroidTest.xml
new file mode 100644
index 0000000..2e69534
--- /dev/null
+++ b/tests/tests/renderscript/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for Renderscript Tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsRenderscriptTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.renderscript.cts" />
+        <option name="runtime-hint" value="9m35s" />
+    </test>
+</configuration>
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java b/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java
index 666d9c5..b8fbdfe 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java
@@ -25,7 +25,7 @@
 import android.renderscript.cts.RSBaseCompute;
 import android.util.Log;
 
-import com.android.cts.renderscript.R;
+import android.renderscript.cts.R;
 
 import java.io.IOException;
 
diff --git a/tests/tests/renderscriptlegacy/Android.mk b/tests/tests/renderscriptlegacy/Android.mk
index 31d8ed9..6aca19b 100644
--- a/tests/tests/renderscriptlegacy/Android.mk
+++ b/tests/tests/renderscriptlegacy/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := 19
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/renderscriptlegacy/AndroidManifest.xml b/tests/tests/renderscriptlegacy/AndroidManifest.xml
index 0c0498a..bd1184f 100644
--- a/tests/tests/renderscriptlegacy/AndroidManifest.xml
+++ b/tests/tests/renderscriptlegacy/AndroidManifest.xml
@@ -19,7 +19,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.renderscriptlegacy">
+    package="android.renderscriptlegacy.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -28,7 +28,7 @@
 
     <!-- This is a self-instrumenting test package. -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.renderscriptlegacy"
+                     android:targetPackage="android.renderscriptlegacy.cts"
                      android:label="CTS tests of Renderscript component">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/renderscriptlegacy/AndroidTest.xml b/tests/tests/renderscriptlegacy/AndroidTest.xml
new file mode 100644
index 0000000..3523dfe
--- /dev/null
+++ b/tests/tests/renderscriptlegacy/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for Renderscript legacy Tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsRenderscriptLegacyTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.renderscriptlegacy.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/rscpp/Android.mk b/tests/tests/rscpp/Android.mk
index 0eb32b5..35e61fa 100644
--- a/tests/tests/rscpp/Android.mk
+++ b/tests/tests/rscpp/Android.mk
@@ -35,5 +35,8 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
 include $(LOCAL_PATH)/librscpptest/Android.mk
diff --git a/tests/tests/rscpp/AndroidManifest.xml b/tests/tests/rscpp/AndroidManifest.xml
index b68ebc3..035d242 100644
--- a/tests/tests/rscpp/AndroidManifest.xml
+++ b/tests/tests/rscpp/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.rscpp">
+    package="android.rscpp.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -24,7 +24,7 @@
 
     <!-- This is a self-instrumenting test package. -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.rscpp"
+                     android:targetPackage="android.rscpp.cts"
                      android:label="CTS tests of RenderScript C++ component">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/rscpp/AndroidTest.xml b/tests/tests/rscpp/AndroidTest.xml
new file mode 100644
index 0000000..1e7c41f
--- /dev/null
+++ b/tests/tests/rscpp/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for renderscript cpp Tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsRsCppTestCases.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.rscpp.cts" />
+        <option name="runtime-hint" value="2m" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/rscpp/librscpptest/clear_object.rs b/tests/tests/rscpp/librscpptest/clear_object.rs
index 70ba42b..cb6a0ad 100644
--- a/tests/tests/rscpp/librscpptest/clear_object.rs
+++ b/tests/tests/rscpp/librscpptest/clear_object.rs
@@ -1,5 +1,5 @@
 #pragma version(1)
-#pragma rs java_package_name(com.android.cts.rscpp)
+#pragma rs java_package_name(android.rscpp.cts)
 
 rs_allocation allocation;
 
diff --git a/tests/tests/rscpp/librscpptest/fe_all.rs b/tests/tests/rscpp/librscpptest/fe_all.rs
index dc20ba7..d5076bf 100644
--- a/tests/tests/rscpp/librscpptest/fe_all.rs
+++ b/tests/tests/rscpp/librscpptest/fe_all.rs
@@ -1,5 +1,5 @@
 #pragma version(1)
-#pragma rs java_package_name(com.android.cts.rscpp)
+#pragma rs java_package_name(android.rscpp.cts)
 
 void test_i8(const char *ain, uchar *aout) {
     aout[0] = ain[0] + 1;
diff --git a/tests/tests/rscpp/librscpptest/setelementat.rs b/tests/tests/rscpp/librscpptest/setelementat.rs
index 5a84552..fc706de 100644
--- a/tests/tests/rscpp/librscpptest/setelementat.rs
+++ b/tests/tests/rscpp/librscpptest/setelementat.rs
@@ -1,5 +1,5 @@
 #pragma version(1)
-#pragma rs java_package_name(com.android.cts.rscpp)
+#pragma rs java_package_name(android.rscpp.cts)
 #pragma rs_fp_relaxed
 
 int memset_toValue = 0;
diff --git a/tests/tests/rscpp/librscpptest/shared.rsh b/tests/tests/rscpp/librscpptest/shared.rsh
index c5599d7..70668e0 100644
--- a/tests/tests/rscpp/librscpptest/shared.rsh
+++ b/tests/tests/rscpp/librscpptest/shared.rsh
@@ -1,5 +1,5 @@
 #pragma version(1)
-#pragma rs java_package_name(com.android.cts.rscpp)
+#pragma rs java_package_name(android.rscpp.cts)
 
 static int64_t g_time;
 
diff --git a/tests/tests/sax/Android.mk b/tests/tests/sax/Android.mk
index a468778..192edfc 100644
--- a/tests/tests/sax/Android.mk
+++ b/tests/tests/sax/Android.mk
@@ -29,4 +29,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/sax/AndroidManifest.xml b/tests/tests/sax/AndroidManifest.xml
index 63c568b..c15bd7a 100644
--- a/tests/tests/sax/AndroidManifest.xml
+++ b/tests/tests/sax/AndroidManifest.xml
@@ -16,14 +16,14 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.sax">
+    package="android.sax.cts">
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.sax"
+                     android:targetPackage="android.sax.cts"
                      android:label="CTS tests of android.sax">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/sax/AndroidTest.xml b/tests/tests/sax/AndroidTest.xml
new file mode 100644
index 0000000..14ec1c3
--- /dev/null
+++ b/tests/tests/sax/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS SAX test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSaxTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.sax.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index ec36d6d..ecd7aba 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -14,6 +14,55 @@
 
 LOCAL_PATH:= $(call my-dir)
 
+test_executable := CtsAslrMallocTestCases
+list_executable := $(test_executable)_list
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= $(test_executable)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_C_INCLUDES := \
+    external/gtest/include
+
+LOCAL_SRC_FILES := \
+    src/AslrMallocTest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+  libbase \
+  libutils \
+  liblog \
+
+LOCAL_STATIC_LIBRARIES := \
+  libgtest
+
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+include $(BUILD_CTS_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_MODULE := $(list_executable)
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+    src/AslrMallocTest.cpp
+
+LOCAL_CFLAGS := \
+    -DBUILD_ONLY \
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog
+
+include $(BUILD_HOST_NATIVE_TEST)
+
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
@@ -21,7 +70,7 @@
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctstestrunner ctsdeviceutil guava
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctstestrunner ctsdeviceutil compatibility-device-util guava
 
 LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
 
@@ -34,6 +83,9 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 3039f81..7a67b08 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -16,12 +16,13 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.security">
+    package="android.security.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
@@ -39,8 +40,8 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.security"
-                     android:label="CTS tests of com.android.cts.security">
+                     android:targetPackage="android.security.cts"
+                     android:label="CTS tests of android.security.cts">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
new file mode 100644
index 0000000..ddbb4dc
--- /dev/null
+++ b/tests/tests/security/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS security test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSecurityTestCases.apk" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsAslrMallocTestCases->/data/local/tmp/CtsAslrMallocTestCases" />
+        <option name="append-bitness" value="true" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="CtsAslrMallocTestCases" />
+        <option name="runtime-hint" value="3m30s" />
+    </test>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.security.cts" />
+        <option name="runtime-hint" value="3m15s" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 327eefc..07bad55 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -32,9 +32,9 @@
 		android_security_cts_MMapExecutableTest.cpp \
 		android_security_cts_AudioPolicyBinderTest.cpp \
 		android_security_cts_EncryptionTest.cpp \
-		android_security_cts_MediaPlayerInfoLeakTest.cpp \
-		android_security_cts_AudioEffectBinderTest.cpp \
 		android_security_cts_AudioFlingerBinderTest.cpp \
+		android_security_cts_AudioEffectBinderTest.cpp \
+		android_security_cts_MediaPlayerInfoLeakTest.cpp \
 		android_security_cts_StagefrightFoundationTest.cpp
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index 6dc025a..99ceda2 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -27,8 +27,8 @@
 extern int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env);
 extern int register_android_security_cts_AudioFlingerBinderTest(JNIEnv* env);
 extern int register_android_security_cts_EncryptionTest(JNIEnv* env);
-extern int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env);
 extern int register_android_security_cts_AudioEffectBinderTest(JNIEnv* env);
+extern int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env);
 extern int register_android_security_cts_StagefrightFoundationTest(JNIEnv* env);
 
 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
@@ -74,11 +74,15 @@
         return JNI_ERR;
     }
 
-    if (register_android_security_cts_MediaPlayerInfoLeakTest(env)) {
+    if (register_android_security_cts_AudioFlingerBinderTest(env)) {
         return JNI_ERR;
     }
 
-   if (register_android_security_cts_AudioEffectBinderTest(env)) {
+    if (register_android_security_cts_AudioEffectBinderTest(env)) {
+        return JNI_ERR;
+    }
+
+    if (register_android_security_cts_MediaPlayerInfoLeakTest(env)) {
         return JNI_ERR;
     }
 
diff --git a/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
index c916122..fb80d6b 100644
--- a/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
@@ -92,6 +92,9 @@
     status_t status = AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
                                           AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                                           "0", "");
+    if (status != NO_ERROR) {
+        return false;
+    }
 
     bool mute;
     status = AudioSystem::getMasterMute(&mute);
@@ -133,6 +136,9 @@
     status_t status = AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
                                           AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                                           "0", "");
+    if (status != NO_ERROR) {
+        return false;
+    }
 
     float vol;
     status = AudioSystem::getMasterVolume(&vol);
diff --git a/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp b/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
index 350309b..ec7e4bd 100644
--- a/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
@@ -35,6 +35,7 @@
 #include <inttypes.h>
 #include <linux/sysctl.h>
 #include <arpa/inet.h>
+#include <linux/ipc.h>
 
 /*
  * Returns true iff this device is vulnerable to CVE-2013-2094.
@@ -251,6 +252,25 @@
     return true;
 }
 
+#define SHMEMSIZE 0x1 /* request one page */
+static jboolean android_security_cts_NativeCodeTest_doSysVipcTest(JNIEnv*, jobject)
+{
+    key_t key = 0x1a25;
+
+#if defined(__i386__) || (_MIPS_SIM == _MIPS_SIM_ABI32)
+    /* system call does not exist for x86 or mips 32 */
+    return true;
+#else
+    /*
+     * Not supported in bionic. Must directly invoke syscall
+     * Only acceptable errno is ENOSYS: shmget syscall
+     * function not implemented
+     */
+    return ((syscall(SYS_shmget, key, SHMEMSIZE, IPC_CREAT | 0666) == -1)
+                && (errno == ENOSYS));
+#endif
+}
+
 static JNINativeMethod gMethods[] = {
     {  "doPerfEventTest", "()Z",
             (void *) android_security_cts_NativeCodeTest_doPerfEventTest },
@@ -266,6 +286,8 @@
             (void *) android_security_cts_NativeCodeTest_doNvmapIocFromIdTest },
     {  "doPingPongRootTest", "()Z",
             (void *) android_security_cts_NativeCodeTest_doPingPongRootTest },
+    {  "doSysVipcTest", "()Z",
+            (void *) android_security_cts_NativeCodeTest_doSysVipcTest },
 };
 
 int register_android_security_cts_NativeCodeTest(JNIEnv* env)
diff --git a/tests/tests/security/src/AslrMallocTest.cpp b/tests/tests/security/src/AslrMallocTest.cpp
new file mode 100644
index 0000000..6e773cb
--- /dev/null
+++ b/tests/tests/security/src/AslrMallocTest.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AslrMallocTest"
+
+#if !defined(BUILD_ONLY)
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <linux/limits.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <unordered_set>
+#endif
+
+#include <gtest/gtest.h>
+#include <string>
+#include <utils/Log.h>
+
+/* minimum entropy for malloc return addresses */
+const size_t minEntropyBits = 8;
+
+/* test using the following allocation sizes */
+const size_t allocSizes[] = {
+    1 << 8,     // small
+    1 << 16,    // large
+    1 << 23     // huge
+};
+
+/* when started using this argument followed by the allocation size,
+ * performs malloc(size) and prints out the address */
+static const std::string argPrint = "--print-malloc-address";
+
+#if !defined(BUILD_ONLY)
+class AslrMallocTest : public ::testing::Test
+{
+protected:
+    std::string self_;
+
+    AslrMallocTest() {}
+    virtual ~AslrMallocTest() {}
+
+    virtual void SetUp()
+    {
+        /* path to self for exec */
+        char path[PATH_MAX];
+        auto size = readlink("/proc/self/exe", path, sizeof(path));
+        ASSERT_TRUE(size > 0 && size < PATH_MAX);
+        path[size] = '\0';
+        self_ = path;
+    }
+
+    void GetAddress(size_t allocSize, uintptr_t& address)
+    {
+        int fds[2];
+        ASSERT_TRUE(pipe(fds) != -1);
+
+        auto pid = fork();
+        ASSERT_TRUE(pid != -1);
+
+        if (pid == 0) {
+            /* child process */
+            ASSERT_TRUE(TEMP_FAILURE_RETRY(dup2(fds[1], STDOUT_FILENO)) != -1);
+
+            for (auto fd : fds) {
+                TEMP_FAILURE_RETRY(close(fd));
+            }
+
+            /* exec self to print malloc output */
+            ASSERT_TRUE(execl(self_.c_str(), self_.c_str(), argPrint.c_str(),
+                android::base::StringPrintf("%zu", allocSize).c_str(),
+                nullptr) != -1);
+        }
+
+        /* parent process */
+        TEMP_FAILURE_RETRY(close(fds[1]));
+
+        std::string output;
+        ASSERT_TRUE(android::base::ReadFdToString(fds[0], &output));
+        TEMP_FAILURE_RETRY(close(fds[0]));
+
+        int status;
+        ASSERT_TRUE(waitpid(pid, &status, 0) != -1);
+        ASSERT_TRUE(WEXITSTATUS(status) == EXIT_SUCCESS);
+
+        ASSERT_TRUE(android::base::ParseUint(output.c_str(), &address));
+    }
+
+    void TestRandomization()
+    {
+        /* should be sufficient to see minEntropyBits when rounded up */
+        size_t iterations = 2 * (1 << minEntropyBits);
+
+        for (auto size : allocSizes) {
+            ALOGV("running %zu iterations for allocation size %zu",
+                iterations, size);
+
+            /* collect unique return addresses */
+            std::unordered_set<uintptr_t> addresses;
+
+            for (size_t i = 0; i < iterations; ++i) {
+                uintptr_t address;
+                GetAddress(size, address);
+
+                addresses.emplace(address);
+            }
+
+            size_t entropy = static_cast<size_t>(0.5 +
+                                log2(static_cast<double>(addresses.size())));
+
+            ALOGV("%zu bits of entropy for allocation size %zu (minimum %zu)",
+                entropy, size, minEntropyBits);
+            ALOGE_IF(entropy < minEntropyBits,
+                "insufficient entropy for malloc(%zu)", size);
+            ASSERT_TRUE(entropy >= minEntropyBits);
+        }
+    }
+};
+#else /* defined(BUILD_ONLY) */
+class AslrMallocTest : public ::testing::Test
+{
+protected:
+    void TestRandomization() {}
+};
+#endif
+
+TEST_F(AslrMallocTest, testMallocRandomization) {
+    TestRandomization();
+}
+
+int main(int argc, char **argv)
+{
+#if !defined(BUILD_ONLY)
+    if (argc == 3 && argPrint == argv[1]) {
+        size_t size;
+
+        if (!android::base::ParseUint(argv[2], &size)) {
+            return EXIT_FAILURE;
+        }
+
+        printf("%p", malloc(size));
+        return EXIT_SUCCESS;
+    }
+#endif
+
+    testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/tests/tests/security/src/android/security/cts/AslrTest.java b/tests/tests/security/src/android/security/cts/AslrTest.java
index 913b49b..774df87 100644
--- a/tests/tests/security/src/android/security/cts/AslrTest.java
+++ b/tests/tests/security/src/android/security/cts/AslrTest.java
@@ -16,20 +16,89 @@
 
 package android.security.cts;
 
+import android.test.InstrumentationTestCase;
 import junit.framework.TestCase;
 
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import android.cts.util.ReadElf;
 
 /**
  * Verify that ASLR is properly enabled on Android Compatible devices.
  */
-public class AslrTest extends TestCase {
+public class AslrTest extends InstrumentationTestCase {
+
+    private static final int aslrMinEntropyBits = 8;
+
+    private static final String TAG = "AslrTest";
+
+    private String readMappingAddress(String mappingName) throws Exception {
+        ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
+                .executeShellCommand("/system/bin/cat /proc/self/maps");
+
+        BufferedReader reader = new BufferedReader(
+                new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())));
+
+        Pattern p = Pattern.compile("^([a-f0-9]+)\\-.+\\[" + mappingName + "\\]$");
+        String line;
+
+        while ((line = reader.readLine()) != null) {
+            Matcher m = p.matcher(line);
+
+            if (m.matches()) {
+                return m.group(1);
+            }
+        }
+
+        return null;
+    }
+
+    private int calculateEntropyBits(String mappingName) throws Exception {
+        HashMap<String, Integer> addresses = new HashMap<String, Integer>();
+
+        // Sufficient number of iterations to ensure we should see at least
+        // aslrMinEntropyBits 
+        for (int i = 0; i < 2 * (1 << aslrMinEntropyBits); i++) {
+            addresses.put(readMappingAddress(mappingName), 1);
+        }
+
+        double entropy = Math.log(addresses.size()) / Math.log(2);
+
+        Log.i(TAG, String.format("%.1f", entropy) +
+            " bits of entropy for " + mappingName);
+
+        return (int) Math.round(entropy);
+    }
+
+    private void testMappingEntropy(String mappingName) throws Exception {
+        if (readMappingAddress(mappingName) == null) {
+            Log.i(TAG, mappingName + " does not exist");
+            return;
+        }
+
+        int entropy = calculateEntropyBits(mappingName);
+
+        assertTrue("Insufficient " + mappingName + " randomization (" +
+            entropy + " bits, >= " + aslrMinEntropyBits + " required)",
+            entropy >= aslrMinEntropyBits);
+    }
+
+    public void testRandomization() throws Exception {
+        testMappingEntropy("stack");
+        testMappingEntropy("heap");
+        testMappingEntropy("anon:libc_malloc");
+    }
 
     public void testOneExecutableIsPie() throws IOException {
         assertTrue(ReadElf.read(new File("/system/bin/cat")).isPIE());
@@ -51,5 +120,4 @@
             }
         }
     }
-
 }
diff --git a/tests/tests/security/src/android/security/cts/CertificateData.java b/tests/tests/security/src/android/security/cts/CertificateData.java
index 0c311e0..59803d3 100644
--- a/tests/tests/security/src/android/security/cts/CertificateData.java
+++ b/tests/tests/security/src/android/security/cts/CertificateData.java
@@ -73,7 +73,6 @@
       "8C:F4:27:FD:79:0C:3A:D1:66:06:8D:E8:1E:57:EF:BB:93:22:72:D4",
       "2F:78:3D:25:52:18:A7:4A:65:39:71:B5:2C:A2:9C:45:15:6F:E9:19",
       "BA:29:41:60:77:98:3F:F4:F3:EF:F2:31:05:3B:2E:EA:6D:4D:45:FD",
-      "97:81:79:50:D8:1C:96:70:CC:34:D8:09:CF:79:44:31:36:7E:F4:74",
       "85:A4:08:C0:9C:19:3E:5D:51:58:7D:CD:D6:13:30:FD:8C:DE:37:BF",
       "58:11:9F:0E:12:82:87:EA:50:FD:D9:87:45:6F:4F:78:DC:FA:D6:D4",
       "9B:AA:E5:9F:56:EE:21:CB:43:5A:BE:25:93:DF:A7:F0:40:D1:1D:CB",
@@ -82,7 +81,6 @@
       "B4:35:D4:E1:11:9D:1C:66:90:A7:49:EB:B3:94:BD:63:7B:A7:82:B7",
       "A9:E9:78:08:14:37:58:88:F2:05:19:B0:6D:2B:0D:2B:60:16:90:7D",
       "60:D6:89:74:B5:C2:65:9E:8A:0F:C1:88:7C:88:D2:46:69:1B:18:2C",
-      "D2:32:09:AD:23:D3:14:23:21:74:E4:0D:7F:9D:62:13:97:86:63:3A",
       "D8:EB:6B:41:51:92:59:E0:F3:E7:85:00:C0:3D:B6:88:97:C9:EE:FC",
       "66:31:BF:9E:F7:4F:9E:B6:C9:D5:A6:0C:BA:6A:BE:D1:F7:BD:EF:7B",
       "DE:3F:40:BD:50:93:D3:9B:6C:60:F6:DA:BC:07:62:01:00:89:76:C9",
@@ -97,12 +95,10 @@
       "70:17:9B:86:8C:00:A4:FA:60:91:52:22:3F:9F:3E:32:BD:E0:05:62",
       "A0:A1:AB:90:C9:FC:84:7B:3B:12:61:E8:97:7D:5F:D3:22:61:D3:CC",
       "D1:EB:23:A4:6D:17:D6:8F:D9:25:64:C2:F1:F1:60:17:64:D8:E3:49",
-      "A1:DB:63:93:91:6F:17:E4:18:55:09:40:04:15:C7:02:40:B0:AE:6B",
       "B8:01:86:D1:EB:9C:86:A5:41:04:CF:30:54:F3:4C:52:B7:E5:58:C6",
       "2E:14:DA:EC:28:F0:FA:1E:8E:38:9A:4E:AB:EB:26:C0:0A:D3:83:C3",
       "DE:28:F4:A4:FF:E5:B9:2F:A3:C5:03:D1:A3:49:A7:F9:96:2A:82:12",
       "CA:3A:FB:CF:12:40:36:4B:44:B2:16:20:88:80:48:39:19:93:7C:F7",
-      "69:BD:8C:F4:9C:D3:00:FB:59:2E:17:93:CA:55:6A:F3:EC:AA:35:FB",
       "13:2D:0D:45:53:4B:69:97:CD:B2:D5:C3:39:E2:55:76:60:9B:5C:C6",
       "5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25",
       "49:0A:75:74:DE:87:0A:47:FE:58:EE:F6:C7:6B:EB:C6:0B:12:40:99",
@@ -172,7 +168,6 @@
       "89:DF:74:FE:5C:F4:0F:4A:80:F9:E3:37:7D:54:DA:91:E1:01:31:8E",
       "E0:B4:32:2E:B2:F6:A5:68:B6:54:53:84:48:18:4A:50:36:87:43:84",
       "7E:04:DE:89:6A:3E:66:6D:00:E6:87:D3:3F:FA:D9:3B:E8:3D:34:9E",
-      "99:A6:9B:E6:1A:FE:88:6B:4D:2B:82:00:7C:B8:54:FC:31:7E:15:39",
       "6E:3A:55:A4:19:0C:19:5C:93:84:3C:C0:DB:72:2E:31:30:61:F0:B1",
       "31:F1:FD:68:22:63:20:EE:C6:3B:3F:9D:EA:4A:3E:53:7C:7C:39:17",
       "F9:CD:0E:2C:DA:76:24:C1:8F:BD:F0:F0:AB:B6:45:B8:F7:FE:D5:7A",
diff --git a/tests/tests/security/src/android/security/cts/HwRngTest.java b/tests/tests/security/src/android/security/cts/HwRngTest.java
index f9ce6be..7654b6f 100644
--- a/tests/tests/security/src/android/security/cts/HwRngTest.java
+++ b/tests/tests/security/src/android/security/cts/HwRngTest.java
@@ -17,11 +17,10 @@
 package android.security.cts;
 
 import android.cts.util.CtsAndroidTestCase;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
 
-import junit.framework.TestCase;
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
 
 import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
@@ -51,18 +50,19 @@
      * Reports whether the {@code /dev/hw_random} device is found. This test always passes.
      */
     public void testDeviceFilePresent() {
-        ReportLog report = getReportLog();
+        DeviceReportLog report = new DeviceReportLog();
         // Need to report at least one value, otherwise summary won't be logged.
-        report.printValue(
+        report.addValue(
                 DEV_HW_RANDOM + " found",
                 DEV_HW_RANDOM.exists() ? 1 : 0,
                 ResultType.WARNING,
                 ResultUnit.NONE);
-        report.printSummary(
+        report.setSummary(
                 "Hardware RNG exposed",
                 DEV_HW_RANDOM.exists() ? 1 : 0,
                 ResultType.WARNING,
                 ResultUnit.NONE);
+        report.submit(getInstrumentation());
     }
 
     /**
diff --git a/tests/tests/security/src/android/security/cts/MediaMetadataRetrieverTest.java b/tests/tests/security/src/android/security/cts/MediaMetadataRetrieverTest.java
index 06ef5fd..6ae0d69 100644
--- a/tests/tests/security/src/android/security/cts/MediaMetadataRetrieverTest.java
+++ b/tests/tests/security/src/android/security/cts/MediaMetadataRetrieverTest.java
@@ -16,7 +16,7 @@
 
 package android.security.cts;
 
-import com.android.cts.security.R;
+import android.security.cts.R;
 
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
diff --git a/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
index 9dff6dd..5298196 100644
--- a/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
+++ b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
@@ -33,7 +33,7 @@
 import java.io.IOException;
 import java.io.RandomAccessFile;
 
-import com.android.cts.security.R;
+import android.security.cts.R;
 
 public class MediaServerCrashTest extends AndroidTestCase {
     private static final String TAG = "MediaServerCrashTest";
diff --git a/tests/tests/security/src/android/security/cts/NativeCodeTest.java b/tests/tests/security/src/android/security/cts/NativeCodeTest.java
index ab41b4f..5ec6ddc 100644
--- a/tests/tests/security/src/android/security/cts/NativeCodeTest.java
+++ b/tests/tests/security/src/android/security/cts/NativeCodeTest.java
@@ -64,6 +64,15 @@
                    + "https://github.com/torvalds/linux/commit/a134f083e79f",
                    doPingPongRootTest());
     }
+
+    public void testSysVipc() throws Exception {
+        assertTrue("Android does not support Sys V IPC, it must "
+                   + "be removed from the kernel. In the kernel config: "
+                   + "Change \"CONFIG_SYSVIPC=y\" to \"# CONFIG_SYSVIPC is not set\" "
+                   + "and rebuild.",
+                   doSysVipcTest());
+    }
+
     /**
      * Returns true iff this device is vulnerable to CVE-2013-2094.
      * A patch for CVE-2013-2094 can be found at
@@ -140,4 +149,25 @@
      */
     private static native boolean doPingPongRootTest();
 
+    /**
+     * Test that SysV IPC has been removed from the kernel.
+     *
+     * Returns true if SysV IPC has been removed.
+     *
+     * System V IPCs are not compliant with Android's application lifecycle because allocated
+     * resources are not freed by the low memory killer. This lead to global kernel resource leakage.
+     *
+     * For example, there is no way to automatically release a SysV semaphore
+     * allocated in the kernel when:
+     * - a buggy or malicious process exits
+     * - a non-buggy and non-malicious process crashes or is explicitly killed.
+     *
+     * Killing processes automatically to make room for new ones is an
+     * important part of Android's application lifecycle implementation. This means
+     * that, even assuming only non-buggy and non-malicious code, it is very likely
+     * that over time, the kernel global tables used to implement SysV IPCs will fill
+     * up.
+     */
+    private static native boolean doSysVipcTest();
+
 }
diff --git a/tests/tests/security/src/android/security/cts/OpenSSLEarlyCCSTest.java b/tests/tests/security/src/android/security/cts/OpenSSLEarlyCCSTest.java
index 9cdb288..bba75dc 100644
--- a/tests/tests/security/src/android/security/cts/OpenSSLEarlyCCSTest.java
+++ b/tests/tests/security/src/android/security/cts/OpenSSLEarlyCCSTest.java
@@ -26,8 +26,6 @@
 import android.test.InstrumentationTestCase;
 import android.util.Log;
 
-import com.android.cts.security.R;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/tests/tests/security/src/android/security/cts/OpenSSLHeartbleedTest.java b/tests/tests/security/src/android/security/cts/OpenSSLHeartbleedTest.java
index 12fcee4..61a03a1 100644
--- a/tests/tests/security/src/android/security/cts/OpenSSLHeartbleedTest.java
+++ b/tests/tests/security/src/android/security/cts/OpenSSLHeartbleedTest.java
@@ -20,8 +20,6 @@
 import android.test.InstrumentationTestCase;
 import android.util.Log;
 
-import com.android.cts.security.R;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
diff --git a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
index 069fa72..0b76cb5 100644
--- a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
+++ b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
@@ -16,8 +16,6 @@
 
 package android.security.cts;
 
-import com.android.cts.security.R;
-
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -35,10 +33,13 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 public class PackageSignatureTest extends AndroidTestCase {
 
     private static final String TAG = PackageSignatureTest.class.getSimpleName();
+    private static final Pattern TEST_PACKAGE_PATTERN = Pattern.compile("android\\.[^\\.]+\\.cts");
 
     public void testPackageSignatures() throws Exception {
         Set<String> badPackages = new HashSet<String>();
@@ -109,8 +110,8 @@
     private boolean isWhitelistedPackage(String packageName) {
         // Don't check the signatures of CTS test packages on the device.
         // devicesetup is the APK CTS loads to collect information needed in the final report
-        return packageName.startsWith("com.android.cts")
-                || WHITELISTED_PACKAGES.contains(packageName);
+        final Matcher matcher = TEST_PACKAGE_PATTERN.matcher(packageName);
+        return matcher.matches() || WHITELISTED_PACKAGES.contains(packageName);
     }
 
     private static final int DEFAULT_BUFFER_BYTES = 1024 * 4;
diff --git a/tests/tests/security/src/android/security/cts/RestrictedInformationTest.java b/tests/tests/security/src/android/security/cts/RestrictedInformationTest.java
new file mode 100644
index 0000000..d0247e9
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/RestrictedInformationTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.test.AndroidTestCase;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Enumeration;
+import android.content.pm.PackageManager;
+import android.net.wifi.WifiManager;
+import android.content.Context;
+
+/**
+ * Check that restricted information is not available
+ * to the untrusted_app domain
+ */
+public class RestrictedInformationTest extends AndroidTestCase {
+   /*
+    * Test that wifi Mac address is not available through sysfs
+    */
+    public void testWifiMacAddr() throws Exception {
+        /* if wifi does not exist, exit - PASS */
+        PackageManager pm = getContext().getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_WIFI))
+            return;
+
+        /* Wifi exists, but is not on - FAIL */
+        WifiManager wifi = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+        assertTrue("Wifi must be enabled to pass this test.", wifi.isWifiEnabled());
+
+        /* Enumerate through the interfaces */
+        Enumeration<NetworkInterface> theInterfaces = NetworkInterface.getNetworkInterfaces();
+
+        while (theInterfaces.hasMoreElements()) {
+            NetworkInterface netif = theInterfaces.nextElement();
+            String name = netif.getName();
+            /* some devices label wifi network interface as eth */
+            if (!name.contains("wlan") && !name.contains("eth"))
+                continue;
+            /* PASS means that getHardwareAddress throws a socket exception */
+            try {
+                byte[] hwAddr = netif.getHardwareAddress();
+                fail("Mac address for " + name + "is accessible: " + new String(hwAddr) +
+                        "\nTo pass this test, label the address with the sysfs_mac_address\n" +
+                        "selinux label. " +
+                        "e.g. https://android-review.googlesource.com/#/c/162180/1\n");
+            } catch (SocketException se) {/* socket exception if MAC blocked - PASS */}
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 0f79860..6e6ae25 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -22,6 +22,8 @@
  */
 package android.security.cts;
 
+import android.test.AndroidTestCase;
+import android.util.Log;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
 import android.media.MediaPlayer;
@@ -33,7 +35,7 @@
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 
-import com.android.cts.security.R;
+import android.security.cts.R;
 
 
 /**
diff --git a/tests/tests/speech/Android.mk b/tests/tests/speech/Android.mk
index 3ab78b8..e8828ee 100755
--- a/tests/tests/speech/Android.mk
+++ b/tests/tests/speech/Android.mk
@@ -25,6 +25,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_PACKAGE_NAME := CtsSpeechTestCases
 
 # Needed for testing M API
diff --git a/tests/tests/speech/AndroidManifest.xml b/tests/tests/speech/AndroidManifest.xml
index 2e7f0b6..cd5d46c 100755
--- a/tests/tests/speech/AndroidManifest.xml
+++ b/tests/tests/speech/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.speech">
+    package="android.speech.tts.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -34,7 +34,7 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.speech"
+                     android:targetPackage="android.speech.tts.cts"
                      android:label="CTS tests of android.speech">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/speech/AndroidTest.xml b/tests/tests/speech/AndroidTest.xml
new file mode 100644
index 0000000..08df58e
--- /dev/null
+++ b/tests/tests/speech/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Speech test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSpeechTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.speech.tts.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechWrapper.java b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechWrapper.java
index 9d460e2..01ba17a 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechWrapper.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechWrapper.java
@@ -35,7 +35,7 @@
 public class TextToSpeechWrapper {
     private static final String LOG_TAG = "TextToSpeechServiceTest";
 
-    public static final String MOCK_TTS_ENGINE = "com.android.cts.speech";
+    public static final String MOCK_TTS_ENGINE = "android.speech.tts.cts";
 
     private final Context mContext;
     private TextToSpeech mTts;
diff --git a/tests/tests/systemui/Android.mk b/tests/tests/systemui/Android.mk
index 1a15fd2..9ce6e47 100644
--- a/tests/tests/systemui/Android.mk
+++ b/tests/tests/systemui/Android.mk
@@ -19,6 +19,11 @@
 # don't include this package in any target
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
index bf5df5b..2cdb36f 100644
--- a/tests/tests/systemui/AndroidManifest.xml
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -16,7 +16,7 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.systemui">
+    package="android.systemui.cts">
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -27,7 +27,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.systemui">
+                     android:targetPackage="android.systemui.cts">
     </instrumentation>
 
 </manifest>
diff --git a/tests/tests/systemui/AndroidTest.xml b/tests/tests/systemui/AndroidTest.xml
new file mode 100644
index 0000000..d98dae6
--- /dev/null
+++ b/tests/tests/systemui/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS SystemUI test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSystemUiTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.systemui.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/systemui/src/android/systemui/cts/ColorUtils.java b/tests/tests/systemui/src/android/systemui/cts/ColorUtils.java
new file mode 100644
index 0000000..a26b2ad
--- /dev/null
+++ b/tests/tests/systemui/src/android/systemui/cts/ColorUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 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.systemui.cts;
+
+/**
+ * Copies of non-public {@link android.graphics.Color} APIs
+ */
+public class ColorUtils {
+
+    public static float brightness(int argb) {
+        int r = (argb >> 16) & 0xFF;
+        int g = (argb >> 8) & 0xFF;
+        int b = argb & 0xFF;
+
+        int V = Math.max(b, Math.max(r, g));
+
+        return (V / 255.f);
+    }
+
+    public static float hue(int argb) {
+        int r = (argb >> 16) & 0xFF;
+        int g = (argb >> 8) & 0xFF;
+        int b = argb & 0xFF;
+
+        int V = Math.max(b, Math.max(r, g));
+        int temp = Math.min(b, Math.min(r, g));
+
+        float H;
+
+        if (V == temp) {
+            H = 0;
+        } else {
+            final float vtemp = (float) (V - temp);
+            final float cr = (V - r) / vtemp;
+            final float cg = (V - g) / vtemp;
+            final float cb = (V - b) / vtemp;
+
+            if (r == V) {
+                H = cb - cg;
+            } else if (g == V) {
+                H = 2 + cr - cb;
+            } else {
+                H = 4 + cg - cr;
+            }
+
+            H /= 6.f;
+            if (H < 0) {
+                H++;
+            }
+        }
+
+        return H;
+    }
+}
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightStatusBarActivity.java b/tests/tests/systemui/src/android/systemui/cts/LightStatusBarActivity.java
new file mode 100644
index 0000000..b33cc77
--- /dev/null
+++ b/tests/tests/systemui/src/android/systemui/cts/LightStatusBarActivity.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 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.systemui.cts;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+
+/**
+ * An activity that exercises SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+ */
+public class LightStatusBarActivity extends Activity {
+
+    private View mContent;
+
+    public void onCreate(Bundle bundle){
+        super.onCreate(bundle);
+
+        mContent = new View(this);
+        mContent.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT));
+        setContentView(mContent);
+    }
+
+    public void setLightStatusBar(boolean lightStatusBar) {
+        int vis = getWindow().getDecorView().getSystemUiVisibility();
+        if (lightStatusBar) {
+            vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+        } else {
+            vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+        }
+        getWindow().getDecorView().setSystemUiVisibility(vis);
+    }
+
+    public int getTop() {
+        return mContent.getLocationOnScreen()[1];
+    }
+
+    public int getWidth() {
+        return mContent.getWidth();
+    }
+}
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightStatusBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightStatusBarTests.java
new file mode 100644
index 0000000..879eac5
--- /dev/null
+++ b/tests/tests/systemui/src/android/systemui/cts/LightStatusBarTests.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2015 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.systemui.cts;
+
+import android.app.ActivityManager;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.support.test.InstrumentationRegistry;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Test for light status bar.
+ */
+public class LightStatusBarTests extends ActivityInstrumentationTestCase2<LightStatusBarActivity> {
+
+    public static final String TAG = "LightStatusBarTests";
+
+    public static final String DUMP_PATH = "/sdcard/lightstatustest.png";
+
+    public LightStatusBarTests() {
+        super(LightStatusBarActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // As the way to access Instrumentation is changed in the new runner, we need to inject it
+        // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
+        // be marked as deprecated and replaced with ActivityTestRule.
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+    }
+
+    public void testLightStatusBarIcons() throws Throwable {
+        PackageManager pm = getInstrumentation().getContext().getPackageManager();
+        if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+                || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+            // No status bar on TVs and watches.
+            return;
+        }
+
+        if (!ActivityManager.isHighEndGfx()) {
+            // non-highEndGfx devices don't do colored system bars.
+            return;
+        }
+
+        requestLightStatusBar(Color.RED /* background */);
+        Thread.sleep(1000);
+
+        Bitmap bitmap = takeStatusBarScreenshot();
+        Stats s = evaluateLightStatusBarBitmap(bitmap, Color.RED /* background */);
+        boolean success = false;
+
+        try {
+            assertMoreThan("Not enough background pixels", 0.3f,
+                    (float) s.backgroundPixels / s.totalPixels(),
+                    "Is the status bar background showing correctly (solid red)?");
+
+            assertMoreThan("Not enough pixels colored as in the spec", 0.1f,
+                    (float) s.iconPixels / s.foregroundPixels(),
+                    "Are the status bar icons colored according to the spec "
+                            + "(60% black and 24% black)?");
+
+            assertLessThan("Too many lighter pixels lighter than the background", 0.05f,
+                    (float) s.sameHueLightPixels / s.foregroundPixels(),
+                    "Are the status bar icons dark?");
+
+            assertLessThan("Too many pixels with a changed hue", 0.05f,
+                    (float) s.unexpectedHuePixels / s.foregroundPixels(),
+                    "Are the status bar icons color-free?");
+
+            success = true;
+        } finally {
+            if (!success) {
+                Log.e(TAG, "Dumping failed bitmap to " + DUMP_PATH);
+                dumpBitmap(bitmap);
+            }
+        }
+    }
+
+    private void assertMoreThan(String what, float expected, float actual, String hint) {
+        if (!(actual > expected)) {
+            fail(what + ": expected more than " + expected * 100 + "%, but only got " + actual * 100
+                    + "%; " + hint);
+        }
+    }
+
+    private void assertLessThan(String what, float expected, float actual, String hint) {
+        if (!(actual < expected)) {
+            fail(what + ": expected less than " + expected * 100 + "%, but got " + actual * 100
+                    + "%; " + hint);
+        }
+    }
+
+    private void requestLightStatusBar(final int background) throws Throwable {
+        final LightStatusBarActivity activity = getActivity();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.getWindow().setStatusBarColor(background);
+                activity.setLightStatusBar(true);
+            }
+        });
+    }
+
+    private static class Stats {
+        int backgroundPixels;
+        int iconPixels;
+        int sameHueDarkPixels;
+        int sameHueLightPixels;
+        int unexpectedHuePixels;
+
+        int totalPixels() {
+            return backgroundPixels + iconPixels + sameHueDarkPixels
+                    + sameHueLightPixels + unexpectedHuePixels;
+        }
+
+        int foregroundPixels() {
+            return iconPixels + sameHueDarkPixels
+                    + sameHueLightPixels + unexpectedHuePixels;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("{bg=%d, ic=%d, dark=%d, light=%d, bad=%d}",
+                    backgroundPixels, iconPixels, sameHueDarkPixels, sameHueLightPixels,
+                    unexpectedHuePixels);
+        }
+    }
+
+    private Stats evaluateLightStatusBarBitmap(Bitmap bitmap, int background) {
+        int iconColor = 0x99000000;
+        int iconPartialColor = 0x3d000000;
+
+        int mixedIconColor = mixSrcOver(background, iconColor);
+        int mixedIconPartialColor = mixSrcOver(background, iconPartialColor);
+
+        int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
+        bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+        Stats s = new Stats();
+        float eps = 0.005f;
+
+        for (int c : pixels) {
+            if (c == background) {
+                s.backgroundPixels++;
+                continue;
+            }
+
+            // What we expect the icons to be colored according to the spec.
+            if (c == mixedIconColor || c == mixedIconPartialColor) {
+                s.iconPixels++;
+                continue;
+            }
+
+            // Due to anti-aliasing, there will be deviations from the ideal icon color, but it
+            // should still be mostly the same hue.
+            float hueDiff = Math.abs(ColorUtils.hue(background) - ColorUtils.hue(c));
+            if (hueDiff < eps || hueDiff > 1 - eps) {
+                // .. it shouldn't be lighter than the original background though.
+                if (ColorUtils.brightness(c) > ColorUtils.brightness(background)) {
+                    s.sameHueLightPixels++;
+                } else {
+                    s.sameHueDarkPixels++;
+                }
+                continue;
+            }
+
+            s.unexpectedHuePixels++;
+        }
+
+        return s;
+    }
+
+    private void dumpBitmap(Bitmap bitmap) {
+        FileOutputStream fileStream = null;
+        try {
+            fileStream = new FileOutputStream(DUMP_PATH);
+            bitmap.compress(Bitmap.CompressFormat.PNG, 85, fileStream);
+            fileStream.flush();
+        } catch (Exception e) {
+            Log.e(TAG, "Dumping bitmap failed.", e);
+        } finally {
+            if (fileStream != null) {
+                try {
+                    fileStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private int mixSrcOver(int background, int foreground) {
+        int bgAlpha = Color.alpha(background);
+        int bgRed = Color.red(background);
+        int bgGreen = Color.green(background);
+        int bgBlue = Color.blue(background);
+
+        int fgAlpha = Color.alpha(foreground);
+        int fgRed = Color.red(foreground);
+        int fgGreen = Color.green(foreground);
+        int fgBlue = Color.blue(foreground);
+
+        return Color.argb(fgAlpha + (255 - fgAlpha) * bgAlpha / 255,
+                    fgRed + (255 - fgAlpha) * bgRed / 255,
+                    fgGreen + (255 - fgAlpha) * bgGreen / 255,
+                    fgBlue + (255 - fgAlpha) * bgBlue / 255);
+    }
+
+    private Bitmap takeStatusBarScreenshot() {
+        Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
+        return Bitmap.createBitmap(fullBitmap, 0, 0,
+                getActivity().getWidth(), getActivity().getTop());
+    }
+}
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java b/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java
deleted file mode 100644
index 626a179..0000000
--- a/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 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.systemui;
-
-/**
- * Copies of non-public {@link android.graphics.Color} APIs
- */
-public class ColorUtils {
-
-    public static float brightness(int argb) {
-        int r = (argb >> 16) & 0xFF;
-        int g = (argb >> 8) & 0xFF;
-        int b = argb & 0xFF;
-
-        int V = Math.max(b, Math.max(r, g));
-
-        return (V / 255.f);
-    }
-
-    public static float hue(int argb) {
-        int r = (argb >> 16) & 0xFF;
-        int g = (argb >> 8) & 0xFF;
-        int b = argb & 0xFF;
-
-        int V = Math.max(b, Math.max(r, g));
-        int temp = Math.min(b, Math.min(r, g));
-
-        float H;
-
-        if (V == temp) {
-            H = 0;
-        } else {
-            final float vtemp = (float) (V - temp);
-            final float cr = (V - r) / vtemp;
-            final float cg = (V - g) / vtemp;
-            final float cb = (V - b) / vtemp;
-
-            if (r == V) {
-                H = cb - cg;
-            } else if (g == V) {
-                H = 2 + cr - cb;
-            } else {
-                H = 4 + cg - cr;
-            }
-
-            H /= 6.f;
-            if (H < 0) {
-                H++;
-            }
-        }
-
-        return H;
-    }
-}
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java
deleted file mode 100644
index 3722320..0000000
--- a/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2015 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.systemui;
-
-import android.app.Activity;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup.LayoutParams;
-
-
-/**
- * An activity that exercises SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
- */
-public class LightStatusBarActivity extends Activity {
-
-    private View mContent;
-
-    public void onCreate(Bundle bundle){
-        super.onCreate(bundle);
-
-        mContent = new View(this);
-        mContent.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT));
-        setContentView(mContent);
-    }
-
-    public void setLightStatusBar(boolean lightStatusBar) {
-        int vis = getWindow().getDecorView().getSystemUiVisibility();
-        if (lightStatusBar) {
-            vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-        } else {
-            vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-        }
-        getWindow().getDecorView().setSystemUiVisibility(vis);
-    }
-
-    public int getTop() {
-        return mContent.getLocationOnScreen()[1];
-    }
-
-    public int getWidth() {
-        return mContent.getWidth();
-    }
-}
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java
deleted file mode 100644
index b5bfd51..0000000
--- a/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2015 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.systemui;
-
-import android.app.ActivityManager;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.support.test.InstrumentationRegistry;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Test for light status bar.
- */
-public class LightStatusBarTests extends ActivityInstrumentationTestCase2<LightStatusBarActivity> {
-
-    public static final String TAG = "LightStatusBarTests";
-
-    public static final String DUMP_PATH = "/sdcard/lightstatustest.png";
-
-    public LightStatusBarTests() {
-        super(LightStatusBarActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // As the way to access Instrumentation is changed in the new runner, we need to inject it
-        // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
-        // be marked as deprecated and replaced with ActivityTestRule.
-        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
-    }
-
-    public void testLightStatusBarIcons() throws Throwable {
-        PackageManager pm = getInstrumentation().getContext().getPackageManager();
-        if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
-                || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
-                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
-            // No status bar on TVs and watches.
-            return;
-        }
-
-        if (!ActivityManager.isHighEndGfx()) {
-            // non-highEndGfx devices don't do colored system bars.
-            return;
-        }
-
-        requestLightStatusBar(Color.RED /* background */);
-        Thread.sleep(1000);
-
-        Bitmap bitmap = takeStatusBarScreenshot();
-        Stats s = evaluateLightStatusBarBitmap(bitmap, Color.RED /* background */);
-        boolean success = false;
-
-        try {
-            assertMoreThan("Not enough background pixels", 0.3f,
-                    (float) s.backgroundPixels / s.totalPixels(),
-                    "Is the status bar background showing correctly (solid red)?");
-
-            assertMoreThan("Not enough pixels colored as in the spec", 0.1f,
-                    (float) s.iconPixels / s.foregroundPixels(),
-                    "Are the status bar icons colored according to the spec "
-                            + "(60% black and 24% black)?");
-
-            assertLessThan("Too many lighter pixels lighter than the background", 0.05f,
-                    (float) s.sameHueLightPixels / s.foregroundPixels(),
-                    "Are the status bar icons dark?");
-
-            assertLessThan("Too many pixels with a changed hue", 0.05f,
-                    (float) s.unexpectedHuePixels / s.foregroundPixels(),
-                    "Are the status bar icons color-free?");
-
-            success = true;
-        } finally {
-            if (!success) {
-                Log.e(TAG, "Dumping failed bitmap to " + DUMP_PATH);
-                dumpBitmap(bitmap);
-            }
-        }
-    }
-
-    private void assertMoreThan(String what, float expected, float actual, String hint) {
-        if (!(actual > expected)) {
-            fail(what + ": expected more than " + expected * 100 + "%, but only got " + actual * 100
-                    + "%; " + hint);
-        }
-    }
-
-    private void assertLessThan(String what, float expected, float actual, String hint) {
-        if (!(actual < expected)) {
-            fail(what + ": expected less than " + expected * 100 + "%, but got " + actual * 100
-                    + "%; " + hint);
-        }
-    }
-
-    private void requestLightStatusBar(final int background) throws Throwable {
-        final LightStatusBarActivity activity = getActivity();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                activity.getWindow().setStatusBarColor(background);
-                activity.setLightStatusBar(true);
-            }
-        });
-    }
-
-    private static class Stats {
-        int backgroundPixels;
-        int iconPixels;
-        int sameHueDarkPixels;
-        int sameHueLightPixels;
-        int unexpectedHuePixels;
-
-        int totalPixels() {
-            return backgroundPixels + iconPixels + sameHueDarkPixels
-                    + sameHueLightPixels + unexpectedHuePixels;
-        }
-
-        int foregroundPixels() {
-            return iconPixels + sameHueDarkPixels
-                    + sameHueLightPixels + unexpectedHuePixels;
-        }
-
-        @Override
-        public String toString() {
-            return String.format("{bg=%d, ic=%d, dark=%d, light=%d, bad=%d}",
-                    backgroundPixels, iconPixels, sameHueDarkPixels, sameHueLightPixels,
-                    unexpectedHuePixels);
-        }
-    }
-
-    private Stats evaluateLightStatusBarBitmap(Bitmap bitmap, int background) {
-        int iconColor = 0x99000000;
-        int iconPartialColor = 0x3d000000;
-
-        int mixedIconColor = mixSrcOver(background, iconColor);
-        int mixedIconPartialColor = mixSrcOver(background, iconPartialColor);
-
-        int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
-        bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
-
-        Stats s = new Stats();
-        float eps = 0.005f;
-
-        for (int c : pixels) {
-            if (c == background) {
-                s.backgroundPixels++;
-                continue;
-            }
-
-            // What we expect the icons to be colored according to the spec.
-            if (c == mixedIconColor || c == mixedIconPartialColor) {
-                s.iconPixels++;
-                continue;
-            }
-
-            // Due to anti-aliasing, there will be deviations from the ideal icon color, but it
-            // should still be mostly the same hue.
-            float hueDiff = Math.abs(ColorUtils.hue(background) - ColorUtils.hue(c));
-            if (hueDiff < eps || hueDiff > 1 - eps) {
-                // .. it shouldn't be lighter than the original background though.
-                if (ColorUtils.brightness(c) > ColorUtils.brightness(background)) {
-                    s.sameHueLightPixels++;
-                } else {
-                    s.sameHueDarkPixels++;
-                }
-                continue;
-            }
-
-            s.unexpectedHuePixels++;
-        }
-
-        return s;
-    }
-
-    private void dumpBitmap(Bitmap bitmap) {
-        FileOutputStream fileStream = null;
-        try {
-            fileStream = new FileOutputStream(DUMP_PATH);
-            bitmap.compress(Bitmap.CompressFormat.PNG, 85, fileStream);
-            fileStream.flush();
-        } catch (Exception e) {
-            Log.e(TAG, "Dumping bitmap failed.", e);
-        } finally {
-            if (fileStream != null) {
-                try {
-                    fileStream.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
-
-    private int mixSrcOver(int background, int foreground) {
-        int bgAlpha = Color.alpha(background);
-        int bgRed = Color.red(background);
-        int bgGreen = Color.green(background);
-        int bgBlue = Color.blue(background);
-
-        int fgAlpha = Color.alpha(foreground);
-        int fgRed = Color.red(foreground);
-        int fgGreen = Color.green(foreground);
-        int fgBlue = Color.blue(foreground);
-
-        return Color.argb(fgAlpha + (255 - fgAlpha) * bgAlpha / 255,
-                    fgRed + (255 - fgAlpha) * bgRed / 255,
-                    fgGreen + (255 - fgAlpha) * bgGreen / 255,
-                    fgBlue + (255 - fgAlpha) * bgBlue / 255);
-    }
-
-    private Bitmap takeStatusBarScreenshot() {
-        Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
-        return Bitmap.createBitmap(fullBitmap, 0, 0,
-                getActivity().getWidth(), getActivity().getTop());
-    }
-}
diff --git a/tests/tests/telecom/Android.mk b/tests/tests/telecom/Android.mk
index 51d97f5..fc03b68 100644
--- a/tests/tests/telecom/Android.mk
+++ b/tests/tests/telecom/Android.mk
@@ -30,4 +30,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml
index b57e0b6..b4d44db 100644
--- a/tests/tests/telecom/AndroidManifest.xml
+++ b/tests/tests/telecom/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.telecom">
+    package="android.telecom.cts">
     <uses-sdk android:minSdkVersion="21" />
     <uses-permission android:name="android.permission.CALL_PHONE" />>
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
@@ -81,7 +81,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.telecom"
+                     android:targetPackage="android.telecom.cts"
                      android:label="CTS tests for android.telecom package">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/telecom/AndroidTest.xml b/tests/tests/telecom/AndroidTest.xml
new file mode 100644
index 0000000..03f64b3
--- /dev/null
+++ b/tests/tests/telecom/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for Telecom Tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.TokenRequirement">
+        <option name="token" value="sim-card" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTelecomTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.telecom.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
index 879c995..0be05d6 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
@@ -35,8 +35,6 @@
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 
-import com.android.cts.telecom.R;
-
 /**
  * Suites of tests that verifies the various Call details.
  */
@@ -55,12 +53,18 @@
             Call.Details.PROPERTY_HIGH_DEF_AUDIO | Call.Details.PROPERTY_WIFI;
     public static final String CALLER_DISPLAY_NAME = "CTS test";
     public static final int CALLER_DISPLAY_NAME_PRESENTATION = TelecomManager.PRESENTATION_ALLOWED;
+    public static final String TEST_SUBJECT = "test";
+    public static final String TEST_CHILD_NUMBER = "650-555-1212";
+    public static final String TEST_FORWARDED_NUMBER = "650-555-1212";
+    public static final String TEST_EXTRA_KEY = "com.test.extra.TEST";
+    public static final int TEST_EXTRA_VALUE = 10;
 
     private StatusHints mStatusHints;
     private Bundle mExtras = new Bundle();
 
     private MockInCallService mInCallService;
     private Call mCall;
+    private Connection mConnection;
 
     @Override
     protected void setUp() throws Exception {
@@ -75,6 +79,7 @@
                             Connection connection = super.onCreateOutgoingConnection(
                                     connectionManagerPhoneAccount,
                                     request);
+                            mConnection = connection;
                             // Modify the connection object created with local values.
                             connection.setConnectionCapabilities(CONNECTION_CAPABILITIES);
                             connection.setCallerDisplayName(
@@ -135,6 +140,95 @@
     }
 
     /**
+     * Tests propagation of the local video capabilities from telephony through to in-call.
+     */
+    public void testCallLocalVideoCapability() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // Note: Local support for video is disabled when a call is in dialing state.
+        mConnection.setConnectionCapabilities(
+                Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
+        assertCallCapabilities(mCall, 0);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX);
+        assertCallCapabilities(mCall, 0);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX);
+        assertCallCapabilities(mCall, 0);
+
+        mConnection.setConnectionCapabilities(
+                Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
+        assertCallCapabilities(mCall, 0);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX);
+        assertCallCapabilities(mCall, 0);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX);
+        assertCallCapabilities(mCall, 0);
+
+        // Set call active; we expect the capabilities to make it through now.
+        mConnection.setActive();
+
+        mConnection.setConnectionCapabilities(
+                Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX);
+
+        mConnection.setConnectionCapabilities(
+                Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX);
+    }
+
+    /**
+     * Tests passing call capabilities from Connections to Calls.
+     */
+    public void testCallCapabilityPropagation() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_CAN_PAUSE_VIDEO);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_CAN_PAUSE_VIDEO);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_HOLD);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_HOLD);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_MANAGE_CONFERENCE);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_MANAGE_CONFERENCE);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_MERGE_CONFERENCE);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_MERGE_CONFERENCE);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_MUTE);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_MUTE);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_RESPOND_VIA_TEXT);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_RESPOND_VIA_TEXT);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORT_HOLD);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_SUPPORT_HOLD);
+
+        mConnection.setConnectionCapabilities(Connection.CAPABILITY_SWAP_CONFERENCE);
+        assertCallCapabilities(mCall, Call.Details.CAPABILITY_SWAP_CONFERENCE);
+    }
+
+    /**
      * Tests whether the getCallerDisplayName() getter returns the correct object.
      */
     public void testCallerDisplayName() {
@@ -279,4 +373,80 @@
 
         assertThat(mCall.getDetails().getVideoState(), is(Integer.class));
     }
+
+    /**
+     * Tests communication of {@link Connection#setExtras(Bundle)} through to
+     * {@link Call.Details#getExtras()}.
+     */
+    public void testExtrasPropagation() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        Bundle exampleExtras = new Bundle();
+        exampleExtras.putString(Connection.EXTRA_CALL_SUBJECT, TEST_SUBJECT);
+        exampleExtras.putString(Connection.EXTRA_CHILD_ADDRESS, TEST_CHILD_NUMBER);
+        exampleExtras.putString(Connection.EXTRA_LAST_FORWARDED_NUMBER, TEST_FORWARDED_NUMBER);
+        exampleExtras.putInt(TEST_EXTRA_KEY, TEST_EXTRA_VALUE);
+        mConnection.setExtras(exampleExtras);
+
+        // Make sure we got back a bundle with the call subject key set.
+        assertCallExtras(mCall, Connection.EXTRA_CALL_SUBJECT);
+
+        Bundle callExtras = mCall.getDetails().getExtras();
+        assertEquals(TEST_SUBJECT, callExtras.getString(Connection.EXTRA_CALL_SUBJECT));
+        assertEquals(TEST_CHILD_NUMBER, callExtras.getString(Connection.EXTRA_CHILD_ADDRESS));
+        assertEquals(TEST_FORWARDED_NUMBER,
+                callExtras.getString(Connection.EXTRA_LAST_FORWARDED_NUMBER));
+        assertEquals(TEST_EXTRA_VALUE, callExtras.getInt(TEST_EXTRA_KEY));
+    }
+
+    /**
+     * Asserts that a call's capabilities are as expected.
+     *
+     * @param call The call.
+     * @param capabilities The expected capabilities.
+     */
+    private void assertCallCapabilities(final Call call, final int capabilities) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return capabilities;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return call.getDetails().getCallCapabilities();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Call should have capabilities " + capabilities
+        );
+    }
+
+    /**
+     * Asserts that a call's extras contain a specified key.
+     *
+     * @param call The call.
+     * @param expectedKey The expected extras key.
+     */
+    private void assertCallExtras(final Call call, final String expectedKey) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expectedKey;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return call.getDetails().getExtras().containsKey(expectedKey) ? expectedKey
+                                : "";
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Call should have extras key " + expectedKey
+        );
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java b/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
index 1fbe0d5..a088951 100644
--- a/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
+++ b/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
@@ -39,8 +39,6 @@
 import android.telecom.VideoProfile;
 import android.test.InstrumentationTestCase;
 
-import com.android.cts.telecom.R;
-
 import java.util.Arrays;
 import java.util.List;
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
index d1a9723..6e124011 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
@@ -37,7 +37,7 @@
 
     // Non-final to allow modification by tests not in this package (e.g. permission-related
     // tests in the Telecom2 test package.
-    public static String PACKAGE = "com.android.cts.telecom";
+    public static String PACKAGE = "android.telecom.cts";
     public static final String COMPONENT = "android.telecom.cts.CtsConnectionService";
     public static final String REMOTE_COMPONENT = "android.telecom.cts.CtsRemoteConnectionService";
     public static final String ACCOUNT_ID = "xtstest_CALL_PROVIDER_ID";
diff --git a/tests/tests/telecom2/Android.mk b/tests/tests/telecom2/Android.mk
index 71edb7b..0932292 100644
--- a/tests/tests/telecom2/Android.mk
+++ b/tests/tests/telecom2/Android.mk
@@ -38,9 +38,12 @@
 
 LOCAL_AAPT_FLAGS := \
     --auto-add-overlay \
-    --extra-packages com.android.cts.telecom \
-    --rename-manifest-package com.android.cts.telecom2 \
+    --extra-packages android.telecom.cts \
+    --rename-manifest-package android.telecom2.cts \
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telecom2/AndroidManifest.xml b/tests/tests/telecom2/AndroidManifest.xml
index e618768..50c6945 100644
--- a/tests/tests/telecom2/AndroidManifest.xml
+++ b/tests/tests/telecom2/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.telecom2">
+    package="android.telecom2.cts">
     <uses-sdk android:minSdkVersion="21" />
 
     <!--
@@ -74,7 +74,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.telecom2"
+                     android:targetPackage="android.telecom2.cts"
                      android:label="CTS tests for android.telecom package">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/telecom2/AndroidTest.xml b/tests/tests/telecom2/AndroidTest.xml
new file mode 100644
index 0000000..e7ae80c
--- /dev/null
+++ b/tests/tests/telecom2/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for Telecom2 Tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTelecomTestCases2.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.telecom2.cts" />
+        <option name="runtime-hint" value="6m42s" />
+    </test>
+</configuration>
diff --git a/tests/tests/telephony/Android.mk b/tests/tests/telephony/Android.mk
index 85864f9..ca766e4 100644
--- a/tests/tests/telephony/Android.mk
+++ b/tests/tests/telephony/Android.mk
@@ -30,6 +30,9 @@
 
 LOCAL_PACKAGE_NAME := CtsTelephonyTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # uncomment when b/13250611 is fixed
 #LOCAL_SDK_VERSION := current
 LOCAL_JAVA_LIBRARIES += android.test.runner
diff --git a/tests/tests/telephony/AndroidManifest.xml b/tests/tests/telephony/AndroidManifest.xml
index a87a54b..6e9545a 100644
--- a/tests/tests/telephony/AndroidManifest.xml
+++ b/tests/tests/telephony/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.telephony">
+    package="android.telephony.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -38,7 +38,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.telephony"
+                     android:targetPackage="android.telephony.cts"
                      android:label="CTS tests of android.telephony">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/telephony/AndroidTest.xml b/tests/tests/telephony/AndroidTest.xml
new file mode 100644
index 0000000..2e6011b
--- /dev/null
+++ b/tests/tests/telephony/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Telephony test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.TokenRequirement">
+        <option name="token" value="sim-card" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTelephonyTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.telephony.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/telephony2/Android.mk b/tests/tests/telephony2/Android.mk
index f405210..792f819 100644
--- a/tests/tests/telephony2/Android.mk
+++ b/tests/tests/telephony2/Android.mk
@@ -28,6 +28,9 @@
 
 LOCAL_PACKAGE_NAME := CtsTelephony2TestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_JAVA_LIBRARIES += android.test.runner
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telephony2/AndroidManifest.xml b/tests/tests/telephony2/AndroidManifest.xml
index 369f75e..6b8ec0c 100644
--- a/tests/tests/telephony2/AndroidManifest.xml
+++ b/tests/tests/telephony2/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.telephony2">
+    package="android.telephony2.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
 
@@ -24,7 +24,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.telephony2">
+                     android:targetPackage="android.telephony2.cts">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/telephony2/AndroidTest.xml b/tests/tests/telephony2/AndroidTest.xml
new file mode 100644
index 0000000..45ee5fa
--- /dev/null
+++ b/tests/tests/telephony2/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Telephony test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTelephony2TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.telephony2.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/text/Android.mk b/tests/tests/text/Android.mk
index 7b2def1..8e80da8 100644
--- a/tests/tests/text/Android.mk
+++ b/tests/tests/text/Android.mk
@@ -29,6 +29,9 @@
 
 LOCAL_PACKAGE_NAME := CtsTextTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/text/AndroidManifest.xml b/tests/tests/text/AndroidManifest.xml
index 99a6ad5..864f655 100644
--- a/tests/tests/text/AndroidManifest.xml
+++ b/tests/tests/text/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.text">
+    package="android.text.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
@@ -67,11 +67,10 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.text"
+                     android:targetPackage="android.text.cts"
                      android:label="CTS tests of android.text">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
 
 </manifest>
-
diff --git a/tests/tests/text/AndroidTest.xml b/tests/tests/text/AndroidTest.xml
new file mode 100644
index 0000000..4b9d24d
--- /dev/null
+++ b/tests/tests/text/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Text test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.WifiCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTextTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.text.cts" />
+        <option name="runtime-hint" value="3m8s" />
+    </test>
+</configuration>
diff --git a/tests/tests/text/src/android/text/cts/BidiFormatterTest.java b/tests/tests/text/src/android/text/cts/BidiFormatterTest.java
index 5ace8b2..3e5db4d 100644
--- a/tests/tests/text/src/android/text/cts/BidiFormatterTest.java
+++ b/tests/tests/text/src/android/text/cts/BidiFormatterTest.java
@@ -33,7 +33,7 @@
             new BidiFormatter.Builder(true /* RTL context */).stereoReset(false).build();
 
     private static final String EN = "abba";
-    private static final String HE = "\u05e0\u05e1";
+    private static final String HE = "\u05E0\u05E1";
 
     private static final String LRM = "\u200E";
     private static final String RLM = "\u200F";
@@ -49,6 +49,18 @@
         assertEquals(true, BidiFormatter.getInstance(true).isRtlContext());
     }
 
+    public void testCachedInstances() {
+        // Test that we get the same cached static instances for simple cases
+        BidiFormatter defaultFormatterInstance = BidiFormatter.getInstance();
+        assertTrue(defaultFormatterInstance == LTR_FMT || defaultFormatterInstance == RTL_FMT);
+
+        assertEquals(LTR_FMT, BidiFormatter.getInstance(false));
+        assertEquals(RTL_FMT, BidiFormatter.getInstance(true));
+
+        assertEquals(LTR_FMT, BidiFormatter.getInstance(false));
+        assertEquals(RTL_FMT, BidiFormatter.getInstance(Locale.forLanguageTag("ar")));
+    }
+
     public void testBuilderIsRtlContext() {
         assertEquals(false, new BidiFormatter.Builder(false).build().isRtlContext());
         assertEquals(true, new BidiFormatter.Builder(true).build().isRtlContext());
diff --git a/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java b/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java
index 195bdf1..cdbc867 100644
--- a/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java
+++ b/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.text.cts;
 
-import com.android.cts.text.R;
+import android.text.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/text/src/android/text/cts/EmojiTest.java b/tests/tests/text/src/android/text/cts/EmojiTest.java
index e1249f3..517d06c 100644
--- a/tests/tests/text/src/android/text/cts/EmojiTest.java
+++ b/tests/tests/text/src/android/text/cts/EmojiTest.java
@@ -33,7 +33,7 @@
 public class EmojiTest extends ActivityInstrumentationTestCase2<EmojiCtsActivity> {
 
     public EmojiTest() {
-        super("com.android.cts.text", EmojiCtsActivity.class);
+        super("android.text.cts", EmojiCtsActivity.class);
     }
 
     protected void setUp() throws Exception {
diff --git a/tests/tests/text/src/android/text/cts/HtmlTest.java b/tests/tests/text/src/android/text/cts/HtmlTest.java
index cf47ab9..0531875 100644
--- a/tests/tests/text/src/android/text/cts/HtmlTest.java
+++ b/tests/tests/text/src/android/text/cts/HtmlTest.java
@@ -198,6 +198,23 @@
                 ret);
     }
 
+    public void testMarkupFromHtml() throws Exception {
+        Spanned s;
+        final int expectedStart = 6;
+        final int expectedEnd = expectedStart + 6;
+
+        String tags[] = {"del", "s", "strike"};
+        for (String tag : tags) {
+            String source = String.format("Hello <%s>struck</%s> world", tag, tag);
+            Spanned spanned = Html.fromHtml(source);
+            Object[] spans = spanned.getSpans(0, spanned.length(), Object.class);
+            assertEquals(1, spans.length);
+            assertEquals(StrikethroughSpan.class, spans[0].getClass());
+            assertEquals(expectedStart, spanned.getSpanStart(spans[0]));
+            assertEquals(expectedEnd, spanned.getSpanEnd(spans[0]));
+        }
+    }
+
     public void testImg() throws Exception {
         Spanned s = Html.fromHtml("yes<img src=\"http://example.com/foo.gif\">no");
         assertEquals("<p dir=\"ltr\">yes<img src=\"http://example.com/foo.gif\">no</p>\n",
diff --git a/tests/tests/text/src/android/text/cts/MyanmarTest.java b/tests/tests/text/src/android/text/cts/MyanmarTest.java
index d59f2b9..9988ab9 100644
--- a/tests/tests/text/src/android/text/cts/MyanmarTest.java
+++ b/tests/tests/text/src/android/text/cts/MyanmarTest.java
@@ -25,7 +25,7 @@
 public class MyanmarTest extends ActivityInstrumentationTestCase2<Activity> {
 
     public MyanmarTest() {
-        super("com.android.cts.text", Activity.class);
+        super("android.text.cts", Activity.class);
     }
 
     protected void setUp() throws Exception {
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java b/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
index 36b081c..4b26eac 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
@@ -553,6 +553,11 @@
         UnderlineSpan span2 = new UnderlineSpan();
         builder.setSpan(span1, 1, 2, Spanned.SPAN_POINT_POINT);
         builder.setSpan(span2, 4, 8, Spanned.SPAN_MARK_POINT);
+
+        Object[] emptySpans = builder.getSpans(0, 10, null);
+        assertNotNull(emptySpans);
+        assertEquals(0, emptySpans.length);
+
         UnderlineSpan[] underlineSpans = builder.getSpans(0, 10, UnderlineSpan.class);
         assertEquals(2, underlineSpans.length);
         assertSame(span1, underlineSpans[0]);
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index 329db88..9dca753 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -980,6 +980,27 @@
         }
     }
 
+    public void testGetOffsetForHorizontal_Multilines() {
+        // Emoticons for surrogate pairs tests.
+        String testString = "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03\uD83D\uDE04";
+        final float width = mDefaultPaint.measureText(testString, 0, 6);
+        StaticLayout layout = new StaticLayout(testString, mDefaultPaint, (int)width,
+                DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+        // We expect the line break to be after the third emoticon, but we allow flexibility of the
+        // line break algorithm as long as the break is within the string. These other cases might
+        // happen if for example the font has kerning between emoticons.
+        final int lineBreakOffset = layout.getOffsetForHorizontal(1, 0.0f);
+        assertEquals(0, layout.getLineForOffset(lineBreakOffset - 1));
+
+        assertEquals(0, layout.getOffsetForHorizontal(0, 0.0f));
+        assertEquals(lineBreakOffset - 2, layout.getOffsetForHorizontal(0, width));
+        assertEquals(lineBreakOffset - 2, layout.getOffsetForHorizontal(0, width * 2));
+
+        final int lineCount = layout.getLineCount();
+        assertEquals(testString.length(), layout.getOffsetForHorizontal(lineCount - 1, width));
+        assertEquals(testString.length(), layout.getOffsetForHorizontal(lineCount - 1, width * 2));
+    }
+
     public void testVeryLargeString() {
         final int MAX_COUNT = 1 << 21;
         final int WORD_SIZE = 32;
diff --git a/tests/tests/text/src/android/text/cts/TextUtilsTest.java b/tests/tests/text/src/android/text/cts/TextUtilsTest.java
index 9258318..0da1eb4 100644
--- a/tests/tests/text/src/android/text/cts/TextUtilsTest.java
+++ b/tests/tests/text/src/android/text/cts/TextUtilsTest.java
@@ -1330,11 +1330,20 @@
     }
 
     public void testIsDigitsOnly() {
+        assertTrue(TextUtils.isDigitsOnly(""));
         assertFalse(TextUtils.isDigitsOnly("no digit"));
         assertFalse(TextUtils.isDigitsOnly("character and 56 digits"));
         assertTrue(TextUtils.isDigitsOnly("0123456789"));
         assertFalse(TextUtils.isDigitsOnly("1234 56789"));
 
+        // U+104A0 OSMANYA DIGIT ZERO
+        assertTrue(TextUtils.isDigitsOnly(new String(Character.toChars(0x104A0))));
+        // U+10858 IMPERIAL ARAMAIC NUMBER ONE
+        assertFalse(TextUtils.isDigitsOnly(new String(Character.toChars(0x10858))));
+
+        assertFalse(TextUtils.isDigitsOnly("\uD801")); // lonely lead surrogate
+        assertFalse(TextUtils.isDigitsOnly("\uDCA0")); // lonely trailing surrogate
+
         try {
             TextUtils.isDigitsOnly(null);
             fail("Should throw NullPointerException!");
@@ -1352,7 +1361,7 @@
 
     public void testIsGraphicChar() {
         assertTrue(TextUtils.isGraphic('a'));
-        assertTrue(TextUtils.isGraphic("\uBA00"));
+        assertTrue(TextUtils.isGraphic('\uBA00'));
 
         // LINE_SEPARATOR
         assertFalse(TextUtils.isGraphic('\u2028'));
@@ -1387,6 +1396,11 @@
 
         assertTrue(TextUtils.isGraphic("a\u2028\u2029\u0085\u0D00\uD800\u0020"));
 
+        assertTrue(TextUtils.isGraphic("\uD83D\uDC0C")); // U+1F40C SNAIL
+        assertFalse(TextUtils.isGraphic("\uDB40\uDC01")); // U+E0000 (unassigned)
+        assertFalse(TextUtils.isGraphic("\uDB3D")); // unpaired high surrogate
+        assertFalse(TextUtils.isGraphic("\uDC0C")); // unpaired low surrogate
+
         try {
             TextUtils.isGraphic(null);
             fail("Should throw NullPointerException!");
diff --git a/tests/tests/text/src/android/text/format/cts/FormatterTest.java b/tests/tests/text/src/android/text/format/cts/FormatterTest.java
index 9c3c45d..6acfb84 100644
--- a/tests/tests/text/src/android/text/format/cts/FormatterTest.java
+++ b/tests/tests/text/src/android/text/format/cts/FormatterTest.java
@@ -32,9 +32,14 @@
         BigDecimal bd = new BigDecimal((long) 1024, mc);
 
         // test different long values with various length
-        assertEquals("0.00 B", Formatter.formatFileSize(mContext, 0));
-
-        assertEquals("899 B", Formatter.formatFileSize(mContext, 899));
+        assertEquals("0 B", Formatter.formatFileSize(mContext, 0));
+        assertEquals("1 B", Formatter.formatFileSize(mContext, 1));
+        assertEquals("9 B", Formatter.formatFileSize(mContext, 9));
+        assertEquals("10 B", Formatter.formatFileSize(mContext, 10));
+        assertEquals("99 B", Formatter.formatFileSize(mContext, 99));
+        assertEquals("100 B", Formatter.formatFileSize(mContext, 100));
+        assertEquals("900 B", Formatter.formatFileSize(mContext, 900));
+        assertEquals("0.88 KB", Formatter.formatFileSize(mContext, 901));
 
         assertEquals("1.00 KB", Formatter.formatFileSize(mContext, bd.pow(1).longValue()));
 
@@ -49,7 +54,7 @@
         assertEquals("1024 PB", Formatter.formatFileSize(mContext, bd.pow(6).longValue()));
 
         // test Negative value
-        assertEquals("-1.00 B", Formatter.formatFileSize(mContext, -1));
+        assertEquals("-1 B", Formatter.formatFileSize(mContext, -1));
     }
 
     public void testFormatIpAddress() {
diff --git a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
index 482edb0..c7a6041 100644
--- a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
@@ -56,7 +56,7 @@
     private MyMetaKeyKeyListener mMetaListener;
 
     public ArrowKeyMovementMethodTest() {
-        super("com.android.cts.text", CtsActivity.class);
+        super("android.text.cts", CtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java b/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java
index 382fc77..6ab79ad 100644
--- a/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java
+++ b/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java
@@ -35,7 +35,7 @@
     private Activity mActivity;
 
     public CharacterPickerDialogTest() {
-        super("com.android.cts.text", CtsActivity.class);
+        super("android.text.cts", CtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java b/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
index c6483a2..c14f463 100644
--- a/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
+++ b/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.text.method.cts;
 
-import com.android.cts.text.R;
+import android.text.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java b/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
index 8bb2adf..4f89ff3 100644
--- a/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
+++ b/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
@@ -16,7 +16,7 @@
 
 package android.text.method.cts;
 
-import com.android.cts.text.R;
+import android.text.cts.R;
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
diff --git a/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
index 336921a..520b91f 100644
--- a/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
@@ -56,7 +56,7 @@
     private MockClickableSpan mClickable1;
 
     public LinkMovementMethodTest() {
-        super("com.android.cts.text", CtsActivity.class);
+        super("android.text.cts", CtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
index 72a8e72..ea679c5 100644
--- a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
@@ -63,7 +63,7 @@
     private CharSequence mTransformedText;
 
     public PasswordTransformationMethodTest() {
-        super("com.android.cts.text", CtsActivity.class);
+        super("android.text.cts", CtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java
index dadce15..6b3e149 100644
--- a/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java
@@ -37,7 +37,7 @@
     private EditText mEditText;
 
     public ReplacementTransformationMethodTest() {
-        super("com.android.cts.text", CtsActivity.class);
+        super("android.text.cts", CtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
index a8d68dc..49196bdc 100644
--- a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
@@ -54,7 +54,7 @@
     private int mScaledTouchSlop;
 
     public ScrollingMovementMethodTest() {
-        super("com.android.cts.text", CtsActivity.class);
+        super("android.text.cts", CtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
index 460ce3d..1756a0f 100644
--- a/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
@@ -28,7 +28,7 @@
 public class SingleLineTransformationMethodTest
         extends ActivityInstrumentationTestCase2<CtsActivity> {
     public SingleLineTransformationMethodTest() {
-        super("com.android.cts.text", CtsActivity.class);
+        super("android.text.cts", CtsActivity.class);
     }
 
     public void testConstructor() {
diff --git a/tests/tests/text/src/android/text/method/cts/TouchTest.java b/tests/tests/text/src/android/text/method/cts/TouchTest.java
index 343847e..3e26084 100644
--- a/tests/tests/text/src/android/text/method/cts/TouchTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TouchTest.java
@@ -43,7 +43,7 @@
     private boolean mReturnFromTouchEvent;
 
     public TouchTest() {
-        super("com.android.cts.text", CtsActivity.class);
+        super("android.text.cts", CtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/text/src/android/text/style/cts/DrawableMarginSpanTest.java b/tests/tests/text/src/android/text/style/cts/DrawableMarginSpanTest.java
index 3813a94..775f035 100644
--- a/tests/tests/text/src/android/text/style/cts/DrawableMarginSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/DrawableMarginSpanTest.java
@@ -16,7 +16,7 @@
 
 package android.text.style.cts;
 
-import com.android.cts.text.R;
+import android.text.cts.R;
 
 
 import android.graphics.Canvas;
diff --git a/tests/tests/text/src/android/text/style/cts/DynamicDrawableSpanTest.java b/tests/tests/text/src/android/text/style/cts/DynamicDrawableSpanTest.java
index 9723556..8a178f8 100644
--- a/tests/tests/text/src/android/text/style/cts/DynamicDrawableSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/DynamicDrawableSpanTest.java
@@ -16,7 +16,7 @@
 
 package android.text.style.cts;
 
-import com.android.cts.text.R;
+import android.text.cts.R;
 
 
 import android.graphics.Canvas;
diff --git a/tests/tests/text/src/android/text/style/cts/ImageSpanTest.java b/tests/tests/text/src/android/text/style/cts/ImageSpanTest.java
index 6f056d0..90282b8 100644
--- a/tests/tests/text/src/android/text/style/cts/ImageSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/ImageSpanTest.java
@@ -16,7 +16,7 @@
 
 package android.text.style.cts;
 
-import com.android.cts.text.R;
+import android.text.cts.R;
 
 
 import android.content.Context;
diff --git a/tests/tests/text/src/android/text/style/cts/MockURLSpanTestActivity.java b/tests/tests/text/src/android/text/style/cts/MockURLSpanTestActivity.java
index dbd154b..be06b0d 100644
--- a/tests/tests/text/src/android/text/style/cts/MockURLSpanTestActivity.java
+++ b/tests/tests/text/src/android/text/style/cts/MockURLSpanTestActivity.java
@@ -16,7 +16,7 @@
 
 package android.text.style.cts;
 
-import com.android.cts.text.R;
+import android.text.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/text/src/android/text/style/cts/URLSpanCtsActivity.java b/tests/tests/text/src/android/text/style/cts/URLSpanCtsActivity.java
index 8d885bc..be6c8ae 100644
--- a/tests/tests/text/src/android/text/style/cts/URLSpanCtsActivity.java
+++ b/tests/tests/text/src/android/text/style/cts/URLSpanCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.text.style.cts;
 
-import com.android.cts.text.R;
+import android.text.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/text/src/android/text/style/cts/URLSpanTest.java b/tests/tests/text/src/android/text/style/cts/URLSpanTest.java
index 7cfe56e..330db77 100644
--- a/tests/tests/text/src/android/text/style/cts/URLSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/URLSpanTest.java
@@ -16,7 +16,7 @@
 
 package android.text.style.cts;
 
-import com.android.cts.text.R;
+import android.text.cts.R;
 
 
 import android.app.Activity;
@@ -33,7 +33,7 @@
     private Activity mActivity;
 
     public URLSpanTest() {
-        super("com.android.cts.text", URLSpanCtsActivity.class);
+        super("android.text.cts", URLSpanCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
index e6b91eb..e7d5ce2 100644
--- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
+++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
@@ -20,6 +20,7 @@
 import android.test.AndroidTestCase;
 import android.text.Spannable;
 import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
 import android.text.style.URLSpan;
 import android.text.util.Linkify;
 import android.text.util.Linkify.MatchFilter;
@@ -349,4 +350,19 @@
 
         assertFalse(Linkify.addLinks((Spannable) null, 0));
     }
+
+    public void testAddLinks_acceptsUrlsWithCommasInRequestParameterValues() throws Exception {
+        String url = "https://android.com/path?ll=37.4221,-122.0836&z=17&pll=37.4221,-122.0836";
+        Spannable spannable = new SpannableString(url);
+
+        Linkify.addLinks(spannable, Linkify.WEB_URLS);
+
+        URLSpan[] urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+        assertEquals("Web URL parsing should accept commas", url, urlSpans[0].getURL());
+        assertEquals("Spannable should start from beginning of the given URL", 0,
+                spannable.getSpanStart(urlSpans[0]));
+        assertEquals("Spannable should end at the end of the given URL", url.length(),
+                spannable.getSpanEnd(urlSpans[0]));
+    }
+
 }
diff --git a/tests/tests/textureview/Android.mk b/tests/tests/textureview/Android.mk
index f85a738..44fc659 100644
--- a/tests/tests/textureview/Android.mk
+++ b/tests/tests/textureview/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_PACKAGE_NAME := CtsTextureViewTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/textureview/AndroidManifest.xml b/tests/tests/textureview/AndroidManifest.xml
index 9ec3f17..6832059 100644
--- a/tests/tests/textureview/AndroidManifest.xml
+++ b/tests/tests/textureview/AndroidManifest.xml
@@ -14,8 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.textureview"
-    >
+    package="android.textureview.cts">
 
     <uses-feature android:glEsVersion="0x00020000" android:required="true" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
@@ -24,7 +23,7 @@
     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
 
     <instrumentation
-        android:targetPackage="com.android.cts.textureview"
+        android:targetPackage="android.textureview.cts"
         android:name="android.support.test.runner.AndroidJUnitRunner" >
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/textureview/AndroidTest.xml b/tests/tests/textureview/AndroidTest.xml
new file mode 100644
index 0000000..d60a4a3
--- /dev/null
+++ b/tests/tests/textureview/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS TextureView test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTextureViewTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.textureview.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/theme/Android.mk b/tests/tests/theme/Android.mk
index 134af7c..44d33c4 100644
--- a/tests/tests/theme/Android.mk
+++ b/tests/tests/theme/Android.mk
@@ -16,7 +16,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := CtsThemeTestCases
+LOCAL_PACKAGE_NAME := CtsThemeDeviceTestCases
 
 # Don't include this package in any target.
 LOCAL_MODULE_TAGS := optional
@@ -28,6 +28,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/theme/AndroidManifest.xml b/tests/tests/theme/AndroidManifest.xml
index 8232d2b..e3ba0c6 100644
--- a/tests/tests/theme/AndroidManifest.xml
+++ b/tests/tests/theme/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.theme">
+    package="android.theme.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
@@ -24,7 +24,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.theme"
+            android:targetPackage="android.theme.cts"
             android:label="CTS tests for themes">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/theme/AndroidTest.xml b/tests/tests/theme/AndroidTest.xml
new file mode 100644
index 0000000..82bd476
--- /dev/null
+++ b/tests/tests/theme/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Theme test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsThemeDeviceTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.theme.cts" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/theme/src/android/theme/cts/DeviceDefaultActivity.java b/tests/tests/theme/src/android/theme/cts/DeviceDefaultActivity.java
index 139a48f..623282b 100644
--- a/tests/tests/theme/src/android/theme/cts/DeviceDefaultActivity.java
+++ b/tests/tests/theme/src/android/theme/cts/DeviceDefaultActivity.java
@@ -16,7 +16,7 @@
 
 package android.theme.cts;
 
-import com.android.cts.theme.R;
+import android.theme.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/transition/Android.mk b/tests/tests/transition/Android.mk
index 3b48e25..d2f53bd 100644
--- a/tests/tests/transition/Android.mk
+++ b/tests/tests/transition/Android.mk
@@ -28,6 +28,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/transition/AndroidManifest.xml b/tests/tests/transition/AndroidManifest.xml
index 0ce1791..3205f28 100644
--- a/tests/tests/transition/AndroidManifest.xml
+++ b/tests/tests/transition/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.transition">
+    package="android.transition.cts">
     <uses-sdk android:minSdkVersion="11" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
@@ -26,7 +26,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.transition"
+                     android:targetPackage="android.transition.cts"
                      android:label="CTS tests for android.transition package">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/transition/AndroidTest.xml b/tests/tests/transition/AndroidTest.xml
new file mode 100644
index 0000000..5aad82b
--- /dev/null
+++ b/tests/tests/transition/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Transition test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTransitionTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.transition.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java b/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
index df1ba19..13badf3 100644
--- a/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
@@ -15,16 +15,14 @@
  */
 package android.transition.cts;
 
-import com.android.cts.transition.R;
-
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
-import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.transition.Scene;
 import android.transition.TransitionManager;
 import android.transition.TransitionValues;
 import android.transition.Visibility;
+import android.transition.cts.R;
 import android.view.Choreographer;
 import android.view.Choreographer.FrameCallback;
 import android.view.View;
@@ -32,12 +30,14 @@
 import android.widget.FrameLayout;
 
 import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 public class BaseTransitionTest extends ActivityInstrumentationTestCase2<TransitionActivity> {
     protected TransitionActivity mActivity;
     protected FrameLayout mSceneRoot;
     public float mAnimatedValue;
-    protected ArrayList<View> mTargets = new ArrayList<>();
+    protected ArrayList<View> mTargets = new ArrayList<View>();
     protected TestTransition mTransition;
 
     public BaseTransitionTest() {
@@ -58,18 +58,8 @@
         waitForStart(mTransition.listener);
     }
 
-    protected static void waitForStart(SimpleTransitionListener listener) throws InterruptedException {
-        long endTime = SystemClock.uptimeMillis() + 50;
-        synchronized (listener) {
-            while (!listener.started) {
-                long now = SystemClock.uptimeMillis();
-                long waitTime = endTime - now;
-                if (waitTime <= 0) {
-                    throw new InterruptedException();
-                }
-                listener.wait(waitTime);
-            }
-        }
+    protected void waitForStart(SimpleTransitionListener listener) throws InterruptedException {
+        assertTrue(listener.startLatch.await(100, TimeUnit.MILLISECONDS));
     }
 
     protected void waitForEnd(long waitMillis) throws InterruptedException {
@@ -78,17 +68,7 @@
 
     protected static void waitForEnd(SimpleTransitionListener listener, long waitMillis)
             throws InterruptedException {
-        long endTime = SystemClock.uptimeMillis() + waitMillis;
-        synchronized (listener) {
-            while (!listener.ended) {
-                long now = SystemClock.uptimeMillis();
-                long waitTime = endTime - now;
-                if (waitTime <= 0) {
-                    throw new InterruptedException();
-                }
-                listener.wait(waitTime);
-            }
-        }
+        listener.endLatch.await(waitMillis, TimeUnit.MILLISECONDS);
     }
 
     protected void startTransition(final int layoutId) throws Throwable {
@@ -125,31 +105,19 @@
     // Waits at least one frame and it could be more. The animated values should have changed
     // from the previously recorded values by the end of this method.
     protected void waitForAnimationFrame() throws Throwable {
-        final boolean[] tripped = new boolean[] { false };
+        final CountDownLatch latch = new CountDownLatch(1);
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
                 Choreographer.getInstance().postFrameCallbackDelayed(new FrameCallback() {
                     @Override
                     public void doFrame(long frameTimeNanos) {
-                        synchronized (tripped) {
-                            tripped[0] = true;
-                            tripped.notifyAll();
-                        }
+                        latch.countDown();
                     }
                 }, 16); // make sure it is the next animation frame.
             }
         });
-        synchronized (tripped) {
-            long endTime = SystemClock.uptimeMillis() + 60;
-            while (!tripped[0]) {
-                long waitTime = endTime - SystemClock.uptimeMillis();
-                if (waitTime <= 0) {
-                    throw new InterruptedException();
-                }
-                tripped.wait(waitTime);
-            }
-        }
+        assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
     }
 
     public class TestTransition extends Visibility {
@@ -157,7 +125,7 @@
 
         public TestTransition() {
             addListener(listener);
-            setDuration(100);
+            setDuration(200);
         }
 
         @Override
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java b/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java
index f5f076d..9917416 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java
@@ -15,7 +15,7 @@
  */
 package android.transition.cts;
 
-import com.android.cts.transition.R;
+import android.transition.cts.R;
 
 import android.transition.ChangeScroll;
 import android.transition.Transition;
@@ -30,7 +30,7 @@
     public void testChangeScroll() throws Throwable {
         enterScene(R.layout.scene5);
         final Transition transition = new ChangeScroll();
-        transition.setDuration(100);
+        transition.setDuration(200);
         SimpleTransitionListener listener = new SimpleTransitionListener();
         transition.addListener(listener);
         runTestOnUiThread(new Runnable() {
@@ -59,7 +59,7 @@
                 assertTrue(scrollY < 300);
             }
         });
-        waitForEnd(listener, 100);
+        waitForEnd(listener, 250);
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
diff --git a/tests/tests/transition/src/android/transition/cts/SimpleTransitionListener.java b/tests/tests/transition/src/android/transition/cts/SimpleTransitionListener.java
index 113f5a5..fb8596a 100644
--- a/tests/tests/transition/src/android/transition/cts/SimpleTransitionListener.java
+++ b/tests/tests/transition/src/android/transition/cts/SimpleTransitionListener.java
@@ -18,50 +18,43 @@
 import android.transition.Transition;
 import android.transition.Transition.TransitionListener;
 
+import java.util.concurrent.CountDownLatch;
+
 /**
  * Listener captures whether each of the methods is called.
  */
 class SimpleTransitionListener implements TransitionListener {
     public Transition transition;
 
-    public boolean started;
-
-    public boolean ended;
-
-    public boolean canceled;
-
-    public boolean paused;
-
-    public boolean resumed;
+    public CountDownLatch startLatch = new CountDownLatch(1);
+    public CountDownLatch endLatch = new CountDownLatch(1);
+    public CountDownLatch cancelLatch = new CountDownLatch(1);
+    public CountDownLatch pauseLatch = new CountDownLatch(1);
+    public CountDownLatch resumeLatch = new CountDownLatch(1);
 
     @Override
-    public synchronized void onTransitionStart(Transition transition) {
-        started = true;
+    public void onTransitionStart(Transition transition) {
         this.transition = transition;
-        notifyAll();
+        startLatch.countDown();
     }
 
     @Override
-    public synchronized void onTransitionEnd(Transition transition) {
-        ended = true;
-        notifyAll();
+    public void onTransitionEnd(Transition transition) {
+        endLatch.countDown();
     }
 
     @Override
-    public synchronized void onTransitionCancel(Transition transition) {
-        canceled = true;
-        notifyAll();
+    public void onTransitionCancel(Transition transition) {
+        cancelLatch.countDown();
     }
 
     @Override
-    public synchronized void onTransitionPause(Transition transition) {
-        paused = true;
-        notifyAll();
+    public void onTransitionPause(Transition transition) {
+        pauseLatch.countDown();
     }
 
     @Override
-    public synchronized void onTransitionResume(Transition transition) {
-        resumed = true;
-        notifyAll();
+    public void onTransitionResume(Transition transition) {
+        resumeLatch.countDown();
     }
 }
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionActivity.java b/tests/tests/transition/src/android/transition/cts/TransitionActivity.java
index 8236bd5..be9bf24 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionActivity.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionActivity.java
@@ -31,7 +31,7 @@
 import android.view.ViewGroup;
 import java.util.ArrayList;
 
-import com.android.cts.transition.R;
+import android.transition.cts.R;
 
 public class TransitionActivity extends Activity {
     @Override
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
index 78db908..8e545ec 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
@@ -15,12 +15,15 @@
  */
 package android.transition.cts;
 
-import com.android.cts.transition.R;
+import android.transition.cts.R;
 
 import android.transition.Scene;
 import android.transition.TransitionManager;
 import android.view.View;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 public class TransitionManagerTest extends BaseTransitionTest {
 
     public TransitionManagerTest() {
@@ -38,10 +41,10 @@
         });
 
         waitForStart();
-        waitForEnd(150);
-        assertFalse(mTransition.listener.resumed);
-        assertFalse(mTransition.listener.paused);
-        assertFalse(mTransition.listener.canceled);
+        waitForEnd(300);
+        assertEquals(1, mTransition.listener.resumeLatch.getCount());
+        assertEquals(1, mTransition.listener.pauseLatch.getCount());
+        assertEquals(1, mTransition.listener.cancelLatch.getCount());
         assertNotNull(mTransition.listener.transition);
         assertEquals(TestTransition.class, mTransition.listener.transition.getClass());
         assertTrue(mTransition != mTransition.listener.transition);
@@ -57,11 +60,11 @@
     public void testGo() throws Throwable {
         startTransition(R.layout.scene1);
         waitForStart();
-        waitForEnd(150);
+        waitForEnd(300);
 
-        assertFalse(mTransition.listener.resumed);
-        assertFalse(mTransition.listener.paused);
-        assertFalse(mTransition.listener.canceled);
+        assertEquals(1, mTransition.listener.resumeLatch.getCount());
+        assertEquals(1, mTransition.listener.pauseLatch.getCount());
+        assertEquals(1, mTransition.listener.cancelLatch.getCount());
         assertNotNull(mTransition.listener.transition);
         assertEquals(TestTransition.class, mTransition.listener.transition.getClass());
         assertTrue(mTransition != mTransition.listener.transition);
@@ -87,26 +90,25 @@
         });
 
         waitForStart();
-        waitForEnd(150);
-        assertFalse(mTransition.listener.resumed);
-        assertFalse(mTransition.listener.paused);
-        assertFalse(mTransition.listener.canceled);
+        waitForEnd(300);
+        assertEquals(1, mTransition.listener.resumeLatch.getCount());
+        assertEquals(1, mTransition.listener.pauseLatch.getCount());
+        assertEquals(1, mTransition.listener.cancelLatch.getCount());
         assertNotNull(mTransition.listener.transition);
         assertEquals(TestTransition.class, mTransition.listener.transition.getClass());
         assertTrue(mTransition != mTransition.listener.transition);
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
+                mTransition.listener.startLatch = new CountDownLatch(1);
+                mTransition.listener.endLatch = new CountDownLatch(1);
                 assertNotNull(mActivity.findViewById(R.id.redSquare));
                 assertNotNull(mActivity.findViewById(R.id.greenSquare));
-                mTransition.listener.started = false;
-                mTransition.listener.ended = false;
                 Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
                 transitionManager.transitionTo(scene);
             }
         });
-        Thread.sleep(50);
-        assertFalse(mTransition.listener.started);
+        assertFalse(mTransition.listener.startLatch.await(50, TimeUnit.MILLISECONDS));
         endTransition();
     }
 
@@ -124,8 +126,7 @@
                 transitionManager.transitionTo(scenes[0]);
             }
         });
-        Thread.sleep(50);
-        assertFalse(mTransition.listener.started);
+        assertFalse(mTransition.listener.startLatch.await(100, TimeUnit.MILLISECONDS));
 
         runTestOnUiThread(new Runnable() {
             @Override
@@ -135,23 +136,22 @@
         });
 
         waitForStart();
-        waitForEnd(150);
-        assertFalse(mTransition.listener.resumed);
-        assertFalse(mTransition.listener.paused);
-        assertFalse(mTransition.listener.canceled);
+        waitForEnd(300);
+        assertEquals(1, mTransition.listener.resumeLatch.getCount());
+        assertEquals(1, mTransition.listener.pauseLatch.getCount());
+        assertEquals(1, mTransition.listener.cancelLatch.getCount());
         assertNotNull(mTransition.listener.transition);
         assertEquals(TestTransition.class, mTransition.listener.transition.getClass());
         assertTrue(mTransition != mTransition.listener.transition);
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mTransition.listener.started = false;
-                mTransition.listener.ended = false;
+                mTransition.listener.startLatch = new CountDownLatch(1);
+                mTransition.listener.endLatch = new CountDownLatch(1);
                 transitionManager.transitionTo(scenes[2]);
             }
         });
-        Thread.sleep(50);
-        assertFalse(mTransition.listener.started);
+        assertFalse(mTransition.listener.startLatch.await(50, TimeUnit.MILLISECONDS));
         endTransition();
     }
 
@@ -161,7 +161,7 @@
         startTransition(R.layout.scene1);
         waitForStart();
         endTransition();
-        waitForEnd(50);
+        waitForEnd(100);
     }
 
     public void testEndTransitionsBeforeStarted() throws Throwable {
@@ -175,9 +175,8 @@
                 TransitionManager.endTransitions(mSceneRoot);
             }
         });
-        Thread.sleep(50);
-        assertFalse(mTransition.listener.started);
-        assertFalse(mTransition.listener.ended);
+        assertFalse(mTransition.listener.startLatch.await(100, TimeUnit.MILLISECONDS));
+        assertFalse(mTransition.listener.endLatch.await(10, TimeUnit.MILLISECONDS));
     }
 }
 
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionTest.java b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
index 8a9f3a3..71c85c5 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
@@ -15,7 +15,7 @@
  */
 package android.transition.cts;
 
-import com.android.cts.transition.R;
+import android.transition.cts.R;
 
 import android.animation.ObjectAnimator;
 import android.transition.AutoTransition;
@@ -28,6 +28,8 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import java.util.concurrent.TimeUnit;
+
 public class TransitionTest extends BaseTransitionTest {
 
     public TransitionTest() {
@@ -52,17 +54,17 @@
 
         waitForStart(listener2);
 
-        assertTrue(mTransition.listener.paused);
-        assertTrue(mTransition.listener.resumed);
-        assertFalse(mTransition.listener.canceled);
-        assertFalse(mTransition.listener.ended);
-        assertTrue(mTransition.listener.started);
+        assertEquals(0, mTransition.listener.pauseLatch.getCount());
+        assertEquals(0, mTransition.listener.resumeLatch.getCount());
+        assertEquals(1, mTransition.listener.cancelLatch.getCount());
+        assertEquals(1, mTransition.listener.endLatch.getCount());
+        assertEquals(0, mTransition.listener.startLatch.getCount());
 
-        assertFalse(listener2.paused);
-        assertFalse(listener2.resumed);
-        assertFalse(listener2.canceled);
-        assertFalse(listener2.ended);
-        assertTrue(listener2.started);
+        assertEquals(1, listener2.pauseLatch.getCount());
+        assertEquals(1, listener2.resumeLatch.getCount());
+        assertEquals(1, listener2.cancelLatch.getCount());
+        assertEquals(1, listener2.endLatch.getCount());
+        assertEquals(0, listener2.startLatch.getCount());
         endTransition();
     }
 
@@ -77,8 +79,7 @@
             }
         });
 
-        Thread.sleep(150);
-        assertFalse(mTransition.listener.ended);
+        assertFalse(mTransition.listener.endLatch.await(250, TimeUnit.MILLISECONDS));
     }
 
     public void testAddTargetId() throws Throwable {
diff --git a/tests/tests/tv/Android.mk b/tests/tests/tv/Android.mk
index 795b473..88e41d9 100644
--- a/tests/tests/tv/Android.mk
+++ b/tests/tests/tv/Android.mk
@@ -20,6 +20,9 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsTvTestCases
diff --git a/tests/tests/tv/AndroidManifest.xml b/tests/tests/tv/AndroidManifest.xml
index 79406e0..7acfc94 100644
--- a/tests/tests/tv/AndroidManifest.xml
+++ b/tests/tests/tv/AndroidManifest.xml
@@ -17,7 +17,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.cts.tv">
+        package="android.tv.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
@@ -110,7 +110,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.cts.tv"
+            android:targetPackage="android.tv.cts"
             android:label="Tests for the TV APIs.">
         <meta-data android:name="listener"
                 android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/tv/AndroidTest.xml b/tests/tests/tv/AndroidTest.xml
new file mode 100644
index 0000000..48d5666
--- /dev/null
+++ b/tests/tests/tv/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS TV test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTvTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.tv.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java b/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java
index f5cc2e1..94e8a01 100644
--- a/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java
@@ -27,7 +27,7 @@
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.ArrayMap;
 
-import com.android.cts.tv.R;
+import android.tv.cts.R;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/tests/tv/src/android/media/tv/cts/HardwareSessionTest.java b/tests/tests/tv/src/android/media/tv/cts/HardwareSessionTest.java
index 2f852d7..a7b5805 100644
--- a/tests/tests/tv/src/android/media/tv/cts/HardwareSessionTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/HardwareSessionTest.java
@@ -29,7 +29,7 @@
 import android.net.Uri;
 import android.test.ActivityInstrumentationTestCase2;
 
-import com.android.cts.tv.R;
+import android.tv.cts.R;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
index b4bc6eb..8fd1939 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
@@ -31,7 +31,7 @@
 import android.net.Uri;
 import android.test.AndroidTestCase;
 
-import com.android.cts.tv.R;
+import android.tv.cts.R;
 
 import java.io.InputStream;
 import java.io.OutputStream;
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
index b4c863a..2a3a713 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
@@ -39,7 +39,7 @@
 import android.view.View;
 import android.widget.LinearLayout;
 
-import com.android.cts.tv.R;
+import android.tv.cts.R;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvViewStubActivity.java b/tests/tests/tv/src/android/media/tv/cts/TvViewStubActivity.java
index 5035e14..aa2b09f 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvViewStubActivity.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvViewStubActivity.java
@@ -19,7 +19,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 
-import com.android.cts.tv.R;
+import android.tv.cts.R;
 
 public class TvViewStubActivity extends Activity {
     @Override
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
index 1c59462..db6f2ba 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
@@ -35,7 +35,7 @@
 import android.view.InputEvent;
 import android.view.KeyEvent;
 
-import com.android.cts.tv.R;
+import android.tv.cts.R;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/tests/tests/uiautomation/Android.mk b/tests/tests/uiautomation/Android.mk
index bb0fc19..0564489 100644
--- a/tests/tests/uiautomation/Android.mk
+++ b/tests/tests/uiautomation/Android.mk
@@ -18,6 +18,11 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/uiautomation/AndroidManifest.xml b/tests/tests/uiautomation/AndroidManifest.xml
index d99e999..fba6b4e 100644
--- a/tests/tests/uiautomation/AndroidManifest.xml
+++ b/tests/tests/uiautomation/AndroidManifest.xml
@@ -17,7 +17,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="android.app.cts.uiautomation">
+        package="android.app.uiautomation.cts">
 
   <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
 
@@ -38,7 +38,7 @@
   </application>
 
   <instrumentation android:name="android.support.test.uiautomator.UiAutomatorInstrumentationTestRunner"
-                   android:targetPackage="android.app.cts.uiautomation">
+                   android:targetPackage="android.app.uiautomation.cts">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/uiautomation/AndroidTest.xml b/tests/tests/uiautomation/AndroidTest.xml
new file mode 100644
index 0000000..cf15c6b
--- /dev/null
+++ b/tests/tests/uiautomation/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS UI Automation test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsUiAutomationTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.app.uiautomation.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
index 2f3f48c8..478a3f6 100755
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
@@ -66,7 +66,7 @@
 
             // Find the list to scroll around.
             UiScrollable listView = new UiScrollable(new UiSelector().resourceId(
-                    "android.app.cts.uiautomation:id/list_view"));
+                    "android.app.uiautomation.cts:id/list_view"));
 
             // Scoll a bit.
             listView.scrollToEnd(Integer.MAX_VALUE);
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java
index a798b1b..839a290 100644
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java
@@ -16,7 +16,7 @@
 
 package android.app.uiautomation.cts;
 
-import android.app.cts.uiautomation.R;
+import android.app.uiautomation.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java
index e6fc743..4ba0f74 100644
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java
@@ -17,7 +17,7 @@
 package android.app.uiautomation.cts;
 
 import android.app.Activity;
-import android.app.cts.uiautomation.R;
+import android.app.uiautomation.cts.R;
 import android.os.Bundle;
 import android.view.WindowManager;
 import android.widget.ArrayAdapter;
diff --git a/tests/tests/uidisolation/Android.mk b/tests/tests/uidisolation/Android.mk
index c21b6df..977c432 100644
--- a/tests/tests/uidisolation/Android.mk
+++ b/tests/tests/uidisolation/Android.mk
@@ -21,6 +21,9 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctstestserver
 
 LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
diff --git a/tests/tests/uidisolation/AndroidManifest.xml b/tests/tests/uidisolation/AndroidManifest.xml
index 86efb6f..0d27e37 100644
--- a/tests/tests/uidisolation/AndroidManifest.xml
+++ b/tests/tests/uidisolation/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.uidisolation">
+    package="android.uidisolation.cts">
 
     <uses-library android:name="org.apache.http.legacy" android:required="false" />
 
@@ -34,7 +34,7 @@
    <uses-permission android:name="android.permission.INTERNET"/>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.uidisolation"
+                     android:targetPackage="android.uidisolation.cts"
                      android:label="CTS tests of android.uidisolation">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/uidisolation/AndroidTest.xml b/tests/tests/uidisolation/AndroidTest.xml
new file mode 100644
index 0000000..e7717c0
--- /dev/null
+++ b/tests/tests/uidisolation/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS UID Isolation test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsUidIsolationTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.uidisolation.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/uirendering/Android.mk b/tests/tests/uirendering/Android.mk
index 76707df..33e2a7a 100644
--- a/tests/tests/uirendering/Android.mk
+++ b/tests/tests/uirendering/Android.mk
@@ -19,6 +19,11 @@
 # don't include this package in any target
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
diff --git a/tests/tests/uirendering/AndroidManifest.xml b/tests/tests/uirendering/AndroidManifest.xml
index b8d84a6..8b6e2aa 100644
--- a/tests/tests/uirendering/AndroidManifest.xml
+++ b/tests/tests/uirendering/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.uirendering">
+    package="android.uirendering.cts">
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -27,7 +27,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.uirendering">
+                     android:targetPackage="android.uirendering.cts">
     </instrumentation>
 
 </manifest>
diff --git a/tests/tests/uirendering/AndroidTest.xml b/tests/tests/uirendering/AndroidTest.xml
new file mode 100644
index 0000000..30c99db
--- /dev/null
+++ b/tests/tests/uirendering/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS UI Rendering test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsUiRenderingTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.uirendering.cts" />
+        <option name="runtime-hint" value="3m" />
+    </test>
+</configuration>
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
index 36be5f0f..562b730 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
@@ -15,8 +15,8 @@
  */
 package android.uirendering.cts.bitmapcomparers;
 
-import com.android.cts.uirendering.R;
-import com.android.cts.uirendering.ScriptC_ExactComparer;
+import android.uirendering.cts.R;
+import android.uirendering.cts.ScriptC_ExactComparer;
 
 import android.content.res.Resources;
 import android.renderscript.Allocation;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs
index 899a5cc..6425c17 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs
@@ -1,5 +1,5 @@
 #pragma version(1)
-#pragma rs java_package_name(com.android.cts.uirendering)
+#pragma rs java_package_name(android.uirendering.cts)
 
 int WIDTH;
 int OFFSET;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
index 56d9cf5..4a25695 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
@@ -15,7 +15,7 @@
  */
 package android.uirendering.cts.bitmapcomparers;
 
-import com.android.cts.uirendering.ScriptC_MSSIMComparer;
+import android.uirendering.cts.ScriptC_MSSIMComparer;
 
 import android.content.res.Resources;
 import android.graphics.Color;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs
index 4d8c41b8..b0e86b8 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs
@@ -1,5 +1,5 @@
 #pragma version(1)
-#pragma rs java_package_name(com.android.cts.uirendering)
+#pragma rs java_package_name(android.uirendering.cts)
 
 int WIDTH;
 int HEIGHT;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
index cc2fbba..5cc896b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
@@ -15,8 +15,8 @@
  */
 package android.uirendering.cts.bitmapcomparers;
 
-import com.android.cts.uirendering.R;
-import com.android.cts.uirendering.ScriptC_MeanSquaredComparer;
+import android.uirendering.cts.R;
+import android.uirendering.cts.ScriptC_MeanSquaredComparer;
 
 import android.content.res.Resources;
 import android.graphics.Color;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs
index b37ad13..3b37609 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs
@@ -1,5 +1,5 @@
 #pragma version(1)
-#pragma rs java_package_name(com.android.cts.uirendering)
+#pragma rs java_package_name(android.uirendering.cts)
 
 int REGION_SIZE;
 int WIDTH;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
index f8304ba..6a78f11 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
@@ -15,8 +15,8 @@
  */
 package android.uirendering.cts.bitmapcomparers;
 
-import com.android.cts.uirendering.R;
-import com.android.cts.uirendering.ScriptC_ThresholdDifferenceComparer;
+import android.uirendering.cts.R;
+import android.uirendering.cts.ScriptC_ThresholdDifferenceComparer;
 
 import android.content.res.Resources;
 import android.graphics.Color;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs
index de1a129..8a40ad6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs
@@ -1,5 +1,5 @@
 #pragma version(1)
-#pragma rs java_package_name(com.android.cts.uirendering)
+#pragma rs java_package_name(android.uirendering.cts)
 
 int WIDTH;
 int THRESHOLD;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
index 29755d8..d3fdb7b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -29,7 +29,7 @@
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 public class ExactCanvasTests extends ActivityTestBase {
     private final BitmapComparer mExactComparer = new ExactComparer();
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
index 5833f20..bac3629 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
@@ -29,7 +29,7 @@
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
 
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 public class FontRenderingTests extends ActivityTestBase {
     // Thresholds are barely loose enough for differences between sw and hw renderers.
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
index dfaaaea..37329af 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
@@ -16,7 +16,7 @@
 package android.uirendering.cts.testclasses;
 
 import android.graphics.Point;
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 import android.graphics.Canvas;
 import android.graphics.Color;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
index a5f76dd..a1338bc 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -28,7 +28,7 @@
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.ViewInitializer;
 import android.view.View;
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 public class LayerTests extends ActivityTestBase {
     @SmallTest
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
index ff1e9db..30851b6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
@@ -19,7 +19,7 @@
 import android.graphics.Rect;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 import android.test.suitebuilder.annotation.SmallTest;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
index 38777a2..8c00ecc 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -32,7 +32,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.webkit.WebView;
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 public class PathClippingTests extends ActivityTestBase {
     // draw circle with hole in it, with stroked circle
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
index 85764a6..6500681 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
@@ -30,7 +30,7 @@
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 public class ShaderTests extends ActivityTestBase {
     @SmallTest
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
index 4582935..2ca8bc8 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
@@ -19,7 +19,7 @@
 import android.graphics.Point;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 import android.test.suitebuilder.annotation.SmallTest;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -53,4 +53,4 @@
                 .addLayout(R.layout.simple_shadow_layout, null, true/* HW only */)
                 .runWithVerifier(verifier);
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
index f1f7c99..2db635f0 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
@@ -11,7 +11,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 /**
  * This tests view clipping by modifying properties of blue_padded_layout, and validating
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index 526f4f9..69cb688 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -123,30 +123,10 @@
         getActivity().runOnUiThread(finishRunnable);
     }
 
-    static int[] getBitmapPixels(Bitmap bitmap) {
-        int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
-        bitmap.getPixels(pixels, 0, bitmap.getWidth(),
-                0, 0, bitmap.getWidth(), bitmap.getHeight());
-        return pixels;
-    }
-
-    private Bitmap takeScreenshotImpl(Point testOffset) {
-        Bitmap source = getInstrumentation().getUiAutomation().takeScreenshot();
-        return Bitmap.createBitmap(source, testOffset.x, testOffset.y, TEST_WIDTH, TEST_HEIGHT);
-    }
-
     public Bitmap takeScreenshot(Point testOffset) {
         getInstrumentation().waitForIdleSync();
-        Bitmap bitmap1 = takeScreenshotImpl(testOffset);
-        Bitmap bitmap2;
-        int count = 0;
-        do  {
-            bitmap2 = bitmap1;
-            bitmap1 = takeScreenshotImpl(testOffset);
-            count++;
-        } while (count < MAX_SCREEN_SHOTS &&
-                !Arrays.equals(getBitmapPixels(bitmap2), getBitmapPixels(bitmap1)));
-        return bitmap1;
+        Bitmap source = getInstrumentation().getUiAutomation().takeScreenshot();
+        return Bitmap.createBitmap(source, testOffset.x, testOffset.y, TEST_WIDTH, TEST_HEIGHT);
     }
 
     /**
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
index 57c67bd..f5dba26 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
@@ -27,7 +27,7 @@
 import android.view.ViewTreeObserver;
 import android.webkit.WebView;
 
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 /**
  * A generic activity that uses a view specified by the user.
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ResourceModifier.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ResourceModifier.java
index 5564b96..9538805 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ResourceModifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ResourceModifier.java
@@ -15,7 +15,7 @@
   */
 package android.uirendering.cts.testinfrastructure;
 
-import com.android.cts.uirendering.R;
+import android.uirendering.cts.R;
 
 import android.content.res.Resources;
 import android.graphics.Bitmap;
diff --git a/tests/tests/util/Android.mk b/tests/tests/util/Android.mk
index 44a67dc..b63e637 100644
--- a/tests/tests/util/Android.mk
+++ b/tests/tests/util/Android.mk
@@ -21,6 +21,9 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/util/AndroidManifest.xml b/tests/tests/util/AndroidManifest.xml
index e40087a..8c48735 100644
--- a/tests/tests/util/AndroidManifest.xml
+++ b/tests/tests/util/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.util">
+    package="android.util.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.READ_LOGS" />
@@ -25,7 +25,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.util"
+                     android:targetPackage="android.util.cts"
                      android:label="CTS tests of android.util">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/util/AndroidTest.xml b/tests/tests/util/AndroidTest.xml
new file mode 100644
index 0000000..9af993c
--- /dev/null
+++ b/tests/tests/util/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Util test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsUtilTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.util.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/util/src/android/util/cts/LocaleListTest.java b/tests/tests/util/src/android/util/cts/LocaleListTest.java
new file mode 100644
index 0000000..f824aa8
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/LocaleListTest.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2015 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.util.cts;
+
+import android.os.Parcel;
+import android.util.LocaleList;
+import android.test.AndroidTestCase;
+
+import java.util.Locale;
+
+public class LocaleListTest extends AndroidTestCase {
+    public void testEmptyLocaleList() {
+        LocaleList ll = new LocaleList();
+        assertNotNull(ll);
+        assertTrue(ll.isEmpty());
+        assertEquals(0, ll.size());
+        assertNull(ll.getPrimary());
+        assertNull(ll.get(1));
+        assertNull(ll.get(10));
+
+        ll = new LocaleList((Locale) null);
+        assertNotNull(ll);
+        assertTrue(ll.isEmpty());
+        assertEquals(0, ll.size());
+        assertNull(ll.getPrimary());
+        assertNull(ll.get(1));
+        assertNull(ll.get(10));
+
+        ll = new LocaleList((Locale[]) null);
+        assertNotNull(ll);
+        assertTrue(ll.isEmpty());
+        assertEquals(0, ll.size());
+        assertNull(ll.getPrimary());
+        assertNull(ll.get(1));
+        assertNull(ll.get(10));
+
+        ll = new LocaleList(new Locale[0]);
+        assertNotNull(ll);
+        assertTrue(ll.isEmpty());
+        assertEquals(0, ll.size());
+        assertNull(ll.getPrimary());
+        assertNull(ll.get(1));
+        assertNull(ll.get(10));
+    }
+
+    public void testOneMemberLocaleList() {
+        final LocaleList ll = new LocaleList(Locale.US);
+        assertNotNull(ll);
+        assertFalse(ll.isEmpty());
+        assertEquals(1, ll.size());
+        assertEquals(Locale.US, ll.getPrimary());
+        assertEquals(Locale.US, ll.get(0));
+        assertNull(ll.get(10));
+    }
+
+    public void testTwoMemberLocaleList() {
+        final Locale enPH = Locale.forLanguageTag("en-PH");
+        final Locale[] la = {enPH, Locale.US};
+        final LocaleList ll = new LocaleList(la);
+        assertNotNull(ll);
+        assertFalse(ll.isEmpty());
+        assertEquals(2, ll.size());
+        assertEquals(enPH, ll.getPrimary());
+        assertEquals(enPH, ll.get(0));
+        assertEquals(Locale.US, ll.get(1));
+        assertNull(ll.get(10));
+    }
+
+    public void testNullArguments() {
+        final Locale[] la = {Locale.US, null};
+        LocaleList ll = null;
+        try {
+            ll = new LocaleList(la);
+            fail("Initializing a LocaleList with an array containing null should throw.");
+        } catch (Throwable e) {
+            assertEquals(NullPointerException.class, e.getClass());
+        }
+    }
+
+    public void testRepeatedArguments() {
+        final Locale[] la = {Locale.US, Locale.US};
+        LocaleList ll = null;
+        try {
+            ll = new LocaleList(la);
+            fail("Initializing a LocaleList with an array containing duplicates should throw.");
+        } catch (Throwable e) {
+            assertEquals(IllegalArgumentException.class, e.getClass());
+        }
+    }
+
+    public void testEquals() {
+        final LocaleList empty = new LocaleList();
+        final LocaleList anotherEmpty = new LocaleList();
+        LocaleList oneMember = new LocaleList(Locale.US);
+        LocaleList sameOneMember = new LocaleList(new Locale("en", "US"));
+        LocaleList differentOneMember = new LocaleList(Locale.FRENCH);
+        Locale[] la = {Locale.US, Locale.FRENCH};
+        LocaleList twoMember = new LocaleList(la);
+
+        assertFalse(empty.equals(null));
+        assertFalse(oneMember.equals(null));
+
+        assertFalse(empty.equals(new Object()));
+
+        assertTrue(empty.equals(empty));
+        assertTrue(oneMember.equals(oneMember));
+
+        assertFalse(empty.equals(oneMember));
+        assertFalse(oneMember.equals(twoMember));
+
+        assertFalse(oneMember.equals(differentOneMember));
+
+        assertTrue(empty.equals(anotherEmpty));
+        assertTrue(oneMember.equals(sameOneMember));
+    }
+
+    public void testHashCode() {
+        final LocaleList empty = new LocaleList();
+        final LocaleList anotherEmpty = new LocaleList();
+        Locale[] la1 = {Locale.US};
+        LocaleList oneMember = new LocaleList(la1);
+        LocaleList sameOneMember = new LocaleList(la1);
+
+        assertEquals(empty.hashCode(), anotherEmpty.hashCode());
+        assertEquals(oneMember.hashCode(), sameOneMember.hashCode());
+    }
+
+    public void testToString() {
+        LocaleList ll = new LocaleList();
+        assertEquals("[]", ll.toString());
+
+        final Locale[] la1 = {Locale.US};
+        ll = new LocaleList(la1);
+        assertEquals("["+Locale.US.toString()+"]", ll.toString());
+
+        final Locale[] la2 = {Locale.US, Locale.FRENCH};
+        ll = new LocaleList(la2);
+        assertEquals("["+Locale.US.toString()+","+Locale.FRENCH.toString()+"]", ll.toString());
+    }
+
+    public void testToLanguageTags() {
+        LocaleList ll = new LocaleList();
+        assertEquals("", ll.toLanguageTags());
+
+        final Locale[] la1 = {Locale.US};
+        ll = new LocaleList(la1);
+        assertEquals(Locale.US.toLanguageTag(), ll.toLanguageTags());
+
+        final Locale[] la2 = {Locale.US, Locale.FRENCH};
+        ll = new LocaleList(la2);
+        assertEquals(Locale.US.toLanguageTag()+","+Locale.FRENCH.toLanguageTag(),
+                ll.toLanguageTags());
+    }
+
+    public void testGetEmptyLocaleList() {
+        LocaleList empty = LocaleList.getEmptyLocaleList();
+        LocaleList anotherEmpty = LocaleList.getEmptyLocaleList();
+        LocaleList constructedEmpty = new LocaleList();
+
+        assertEquals(constructedEmpty, empty);
+        assertSame(empty, anotherEmpty);
+    }
+
+    public void testForLanguageTags() {
+        assertEquals(LocaleList.getEmptyLocaleList(), LocaleList.forLanguageTags(null));
+        assertEquals(LocaleList.getEmptyLocaleList(), LocaleList.forLanguageTags(""));
+
+        assertEquals(new LocaleList(Locale.forLanguageTag("en-US")),
+                LocaleList.forLanguageTags("en-US"));
+
+        final Locale[] la = {Locale.forLanguageTag("en-PH"), Locale.forLanguageTag("en-US")};
+        assertEquals(new LocaleList(la), LocaleList.forLanguageTags("en-PH,en-US"));
+    }
+
+    public void testGetDefault() {
+        LocaleList ll = LocaleList.getDefault();
+        assertNotNull(ll);
+        assertTrue(ll.size() >= 1);
+        assertEquals(Locale.getDefault(), ll.getPrimary());
+    }
+
+    public void testParcelable() {
+        // Make sure an empty LocaleList can be marshalled/unmarshalled via Parcel.
+        assertEquals(LocaleList.getEmptyLocaleList(),
+                cloneViaParcel(LocaleList.getEmptyLocaleList()));
+
+        // Make sure a non-empty LocaleList can be marshalled/unmarshalled via Parcel.
+        LocaleList original = LocaleList.forLanguageTags("en-PH,en-US");
+        assertEquals(original, cloneViaParcel(original));
+    }
+
+    private static LocaleList cloneViaParcel(final LocaleList original) {
+        Parcel parcel = null;
+        try {
+            parcel = Parcel.obtain();
+            original.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            return LocaleList.CREATOR.createFromParcel(parcel);
+        } finally {
+            if (parcel != null) {
+                parcel.recycle();
+            }
+        }
+    }
+
+    public void testGetFirstMatch_noAssets() {
+        String[] noAssets = {};
+        assertNull(LocaleList.getEmptyLocaleList().getFirstMatch(noAssets));
+        assertEquals(
+                Locale.forLanguageTag("fr-BE"),
+                LocaleList.forLanguageTags("fr-BE").getFirstMatch(noAssets));
+        assertEquals(
+                Locale.forLanguageTag("fr-BE"),
+                LocaleList.forLanguageTags("fr-BE,nl-BE").getFirstMatch(noAssets));
+    }
+
+    public void testGetFirstMatch_oneAsset() {
+        String[] oneDutchAsset = {"nl"};
+        assertNull(LocaleList.getEmptyLocaleList().getFirstMatch(oneDutchAsset));
+        assertEquals(
+                Locale.forLanguageTag("fr-BE"),
+                LocaleList.forLanguageTags("fr-BE").getFirstMatch(oneDutchAsset));
+        assertEquals(
+                Locale.forLanguageTag("nl-BE"),
+                LocaleList.forLanguageTags("nl-BE").getFirstMatch(oneDutchAsset));
+        assertEquals(
+                Locale.forLanguageTag("nl-BE"),
+                LocaleList.forLanguageTags("fr-BE,nl-BE").getFirstMatch(oneDutchAsset));
+        assertEquals(
+                Locale.forLanguageTag("nl-BE"),
+                LocaleList.forLanguageTags("nl-BE,fr-BE").getFirstMatch(oneDutchAsset));
+    }
+
+    public void testGetFirstMatch_twoAssets() {
+        String[] FrenchAndDutchAssets = {"fr", "nl"};
+        assertNull(LocaleList.getEmptyLocaleList().getFirstMatch(FrenchAndDutchAssets));
+        assertEquals(
+                Locale.forLanguageTag("fr-BE"),
+                LocaleList.forLanguageTags("fr-BE").getFirstMatch(FrenchAndDutchAssets));
+        assertEquals(
+                Locale.forLanguageTag("nl-BE"),
+                LocaleList.forLanguageTags("nl-BE").getFirstMatch(FrenchAndDutchAssets));
+        assertEquals(
+                Locale.forLanguageTag("fr-BE"),
+                LocaleList.forLanguageTags("fr-BE,nl-BE").getFirstMatch(FrenchAndDutchAssets));
+        assertEquals(
+                Locale.forLanguageTag("nl-BE"),
+                LocaleList.forLanguageTags("nl-BE,fr-BE").getFirstMatch(FrenchAndDutchAssets));
+    }
+
+    public void testGetFirstMatch_oneChineseAsset() {
+        String[] oneChineseAsset = {"zh-CN"};  // Assumed to mean zh-Hans-CN
+        // The following Chinese examples would all match, so they will be chosen.
+        assertEquals(
+                Locale.forLanguageTag("zh"),
+                LocaleList.forLanguageTags("ko-KR,zh").getFirstMatch(oneChineseAsset));
+        assertEquals(
+                Locale.forLanguageTag("zh-CN"),
+                LocaleList.forLanguageTags("ko-KR,zh-CN").getFirstMatch(oneChineseAsset));
+        assertEquals(
+                Locale.forLanguageTag("zh-Hans"),
+                LocaleList.forLanguageTags("ko-KR,zh-Hans").getFirstMatch(oneChineseAsset));
+        assertEquals(
+                Locale.forLanguageTag("zh-Hans-CN"),
+                LocaleList.forLanguageTags("ko-KR,zh-Hans-CN").getFirstMatch(oneChineseAsset));
+        assertEquals(
+                Locale.forLanguageTag("zh-Hans-HK"),
+                LocaleList.forLanguageTags("ko-KR,zh-Hans-HK").getFirstMatch(oneChineseAsset));
+
+        // The following Chinese examples wouldn't match, so the first locale will be chosen
+        // instead.
+        assertEquals(
+                Locale.forLanguageTag("ko-KR"),
+                LocaleList.forLanguageTags("ko-KR,zh-TW").getFirstMatch(oneChineseAsset));
+        assertEquals(
+                Locale.forLanguageTag("ko-KR"),
+                LocaleList.forLanguageTags("ko-KR,zh-Hant").getFirstMatch(oneChineseAsset));
+        assertEquals(
+                Locale.forLanguageTag("ko-KR"),
+                LocaleList.forLanguageTags("ko-KR,zh-Hant-TW").getFirstMatch(oneChineseAsset));
+    }
+
+    public void testGetFirstMatch_serbianCyrillic() {
+        String[] oneSerbianAsset = {"sr"};  // Assumed to mean sr-Cyrl-RS
+        // The following Serbian examples would all match, so they will be chosen.
+        assertEquals(
+                Locale.forLanguageTag("sr"),
+                LocaleList.forLanguageTags("hr-HR,sr").getFirstMatch(oneSerbianAsset));
+        assertEquals(
+                Locale.forLanguageTag("sr-RS"),
+                LocaleList.forLanguageTags("hr-HR,sr-RS").getFirstMatch(oneSerbianAsset));
+        assertEquals(
+                Locale.forLanguageTag("sr-Cyrl"),
+                LocaleList.forLanguageTags("hr-HR,sr-Cyrl").getFirstMatch(oneSerbianAsset));
+        assertEquals(
+                Locale.forLanguageTag("sr-Cyrl-RS"),
+                LocaleList.forLanguageTags("hr-HR,sr-Cyrl-RS").getFirstMatch(oneSerbianAsset));
+        assertEquals(
+                Locale.forLanguageTag("sr-Cyrl-ME"),
+                LocaleList.forLanguageTags("hr-HR,sr-Cyrl-ME").getFirstMatch(oneSerbianAsset));
+
+        // The following Serbian examples wouldn't match, so the first locale will be chosen
+        // instead.
+        assertEquals(
+                Locale.forLanguageTag("hr-HR"),
+                LocaleList.forLanguageTags("hr-HR,sr-ME").getFirstMatch(oneSerbianAsset));
+        assertEquals(
+                Locale.forLanguageTag("hr-HR"),
+                LocaleList.forLanguageTags("hr-HR,sr-Latn").getFirstMatch(oneSerbianAsset));
+        assertEquals(
+                Locale.forLanguageTag("hr-HR"),
+                LocaleList.forLanguageTags("hr-HR,sr-Latn-ME").getFirstMatch(oneSerbianAsset));
+    }
+}
diff --git a/tests/tests/util/src/android/util/cts/PatternsTest.java b/tests/tests/util/src/android/util/cts/PatternsTest.java
new file mode 100644
index 0000000..61755ef
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/PatternsTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 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.util.cts;
+
+import android.util.Patterns;
+
+import junit.framework.TestCase;
+
+/**
+ * Test {@link Patterns}.
+ */
+public class PatternsTest extends TestCase {
+
+    public void testWebUrl_matchesUrlsWithCommasInRequestParameterValues() throws Exception {
+        String url = "https://android.com/path?ll=37.4221,-122.0836&z=17&pll=37.4221,-122.0836";
+        assertTrue("WEB_URL pattern should match commas", Patterns.WEB_URL.matcher(url).matches());
+    }
+}
diff --git a/tests/tests/util/src/android/util/cts/PropertyTest.java b/tests/tests/util/src/android/util/cts/PropertyTest.java
new file mode 100644
index 0000000..22ad2c4
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/PropertyTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 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.util.cts;
+
+import android.graphics.Point;
+import android.util.FloatProperty;
+import android.util.IntProperty;
+import android.util.Property;
+import junit.framework.TestCase;
+
+public class PropertyTest extends TestCase {
+
+    float mFloatValue = -1;
+    int mIntValue = -2;
+    Point mPointValue = new Point(-3, -4);
+
+    public void testProperty() throws Exception {
+        float testFloatValue = 5;
+        Point testPointValue = new Point(10, 20);
+
+        assertFalse(getFloatProp() == testFloatValue);
+        assertFalse(getPointProp().equals(testPointValue));
+        assertEquals(RAW_FLOAT_PROP.get(this), getFloatProp());
+        assertEquals(RAW_POINT_PROP.get(this), getPointProp());
+
+        RAW_FLOAT_PROP.set(this, testFloatValue);
+        assertEquals(RAW_FLOAT_PROP.get(this), mFloatValue);
+
+        RAW_POINT_PROP.set(this, testPointValue);
+        assertEquals(RAW_POINT_PROP.get(this), testPointValue);
+    }
+
+    public void testFloatProperty() throws Exception {
+        float testFloatValue = 5;
+
+        assertFalse(getFloatProp() == testFloatValue);
+        assertEquals(FLOAT_PROP.get(this), getFloatProp());
+
+        FLOAT_PROP.set(this, testFloatValue);
+        assertEquals(FLOAT_PROP.get(this), testFloatValue);
+    }
+
+    public void testIntProperty() throws Exception {
+        int testIntValue = 5;
+
+        assertFalse(getIntProp() == testIntValue);
+        assertEquals(INT_PROP.get(this).intValue(), getIntProp());
+
+        INT_PROP.set(this, testIntValue);
+        assertEquals(INT_PROP.get(this).intValue(), testIntValue);
+    }
+
+    // Utility methods to get/set instance values. Used by Property classes below.
+
+    private void setFloatProp(float value) {
+        mFloatValue = value;
+    }
+
+    private float getFloatProp() {
+        return mFloatValue;
+    }
+
+    private void setIntProp(int value) {
+        mIntValue = value;
+    }
+
+    private int getIntProp() {
+        return mIntValue;
+    }
+
+    private void setPointProp(Point value) {
+        mPointValue = value;
+    }
+
+    private Point getPointProp() {
+        return mPointValue;
+    }
+
+    // Properties. RAW subclass from the generic Property class, the others subclass from
+    // the primtive-friendly IntProperty and FloatProperty subclasses.
+
+    public static final Property<PropertyTest, Point> RAW_POINT_PROP =
+            new Property<PropertyTest, Point>(Point.class, "rawPoint") {
+                @Override
+                public void set(PropertyTest object, Point value) {
+                    object.setPointProp(value);
+                }
+
+                @Override
+                public Point get(PropertyTest object) {
+                    return object.getPointProp();
+                }
+            };
+
+    public static final Property<PropertyTest, Float> RAW_FLOAT_PROP =
+            new Property<PropertyTest, Float>(Float.class, "rawFloat") {
+                @Override
+                public void set(PropertyTest object, Float value) {
+                    object.setFloatProp(value);
+                }
+
+                @Override
+                public Float get(PropertyTest object) {
+                    return object.getFloatProp();
+                }
+            };
+
+    public static final Property<PropertyTest, Float> FLOAT_PROP =
+            new FloatProperty<PropertyTest>("float") {
+
+                @Override
+                public void setValue(PropertyTest object, float value) {
+                    object.setFloatProp(value);
+                }
+
+                @Override
+                public Float get(PropertyTest object) {
+                    return object.getFloatProp();
+                }
+            };
+
+    public static final Property<PropertyTest, Integer> INT_PROP =
+            new IntProperty<PropertyTest>("int") {
+
+                @Override
+                public void setValue(PropertyTest object, int value) {
+                    object.setIntProp(value);
+                }
+
+                @Override
+                public Integer get(PropertyTest object) {
+                    return object.getIntProp();
+                }
+            };
+}
diff --git a/tests/tests/util/src/android/util/cts/XmlTest.java b/tests/tests/util/src/android/util/cts/XmlTest.java
index 833bd3c..66918ce 100644
--- a/tests/tests/util/src/android/util/cts/XmlTest.java
+++ b/tests/tests/util/src/android/util/cts/XmlTest.java
@@ -391,7 +391,7 @@
 
     public void testAsAttributeSet() {
         XmlResourceParser xp = getContext().getResources().getLayout(
-                com.android.cts.util.R.layout.xml_test);
+                android.util.cts.R.layout.xml_test);
         int eventType = -1;
         try {
             eventType = xp.getEventType();
diff --git a/tests/tests/view/Android.mk b/tests/tests/view/Android.mk
index 027e321..24a351f 100644
--- a/tests/tests/view/Android.mk
+++ b/tests/tests/view/Android.mk
@@ -21,6 +21,9 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index b7e0076..f4d82cb 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.view">
+    package="android.view.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application android:label="Android TestCase"
@@ -194,7 +194,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.view"
+                     android:targetPackage="android.view.cts"
                      android:label="CTS tests of android.view">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/view/AndroidTest.xml b/tests/tests/view/AndroidTest.xml
new file mode 100644
index 0000000..def111d
--- /dev/null
+++ b/tests/tests/view/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS View test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsViewTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.view.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/view/src/android/view/animation/cts/AccelerateDecelerateInterpolatorTest.java b/tests/tests/view/src/android/view/animation/cts/AccelerateDecelerateInterpolatorTest.java
index 6e80d00..440e390 100644
--- a/tests/tests/view/src/android/view/animation/cts/AccelerateDecelerateInterpolatorTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AccelerateDecelerateInterpolatorTest.java
@@ -16,7 +16,7 @@
 
 package android.view.animation.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.app.Activity;
@@ -41,7 +41,7 @@
     private static final long ALPHA_DURATION = 2000;
 
     public AccelerateDecelerateInterpolatorTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/animation/cts/AccelerateInterpolatorTest.java b/tests/tests/view/src/android/view/animation/cts/AccelerateInterpolatorTest.java
index 51b2b09..b2be24d 100644
--- a/tests/tests/view/src/android/view/animation/cts/AccelerateInterpolatorTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AccelerateInterpolatorTest.java
@@ -16,7 +16,7 @@
 
 package android.view.animation.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.app.Activity;
@@ -36,7 +36,7 @@
         extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
 
     public AccelerateInterpolatorTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     private Activity mActivity;
diff --git a/tests/tests/view/src/android/view/animation/cts/AlphaAnimationTest.java b/tests/tests/view/src/android/view/animation/cts/AlphaAnimationTest.java
index acfe1a6..45eb418 100644
--- a/tests/tests/view/src/android/view/animation/cts/AlphaAnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AlphaAnimationTest.java
@@ -23,7 +23,7 @@
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Transformation;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 /**
  * Test {@link AlphaAnimation}.
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationSetTest.java b/tests/tests/view/src/android/view/animation/cts/AnimationSetTest.java
index 0b3bf49..49c51e0 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationSetTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationSetTest.java
@@ -33,7 +33,7 @@
 import android.view.animation.Transformation;
 import android.view.animation.TranslateAnimation;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 public class AnimationSetTest
@@ -51,7 +51,7 @@
     private Activity mActivity;
 
     public AnimationSetTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationTest.java b/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
index 31440df..bc1af11 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
@@ -16,7 +16,7 @@
 
 package android.view.animation.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.app.Activity;
@@ -51,7 +51,7 @@
     private Object mLockObject = new Object();
 
     public AnimationTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationTestCtsActivity.java b/tests/tests/view/src/android/view/animation/cts/AnimationTestCtsActivity.java
index 1ef9e48..0316f28 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationTestCtsActivity.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationTestCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.view.animation.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationUtilsTest.java b/tests/tests/view/src/android/view/animation/cts/AnimationUtilsTest.java
index 9de0d87..b47613f 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationUtilsTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationUtilsTest.java
@@ -16,7 +16,7 @@
 
 package android.view.animation.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.content.Context;
@@ -35,7 +35,7 @@
     private AnimationTestCtsActivity mActivity;
 
     public AnimationUtilsTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     @Override
@@ -45,7 +45,7 @@
     }
 
     public void testLoad() {
-        // XML file of com.android.cts.view.R.anim.anim_alpha
+        // XML file of android.view.cts.R.anim.anim_alpha
         // <alpha xmlns:android="http://schemas.android.com/apk/res/android"
         //      android:interpolator="@android:anim/accelerate_interpolator"
         //      android:fromAlpha="0.0"
@@ -61,7 +61,7 @@
                 android.R.anim.accelerate_interpolator);
         assertTrue(interpolator instanceof AccelerateInterpolator);
 
-        // Load LayoutAnimationController from com.android.cts.view.R.anim.anim_gridlayout
+        // Load LayoutAnimationController from android.view.cts.R.anim.anim_gridlayout
         // <gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
         //      android:delay="10%"
         //      android:rowDelay="50%"
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java b/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java
index cc8ada0..3851e94 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java
@@ -36,7 +36,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 public class AnimatorInflaterTest
         extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
@@ -45,7 +45,7 @@
     Set<Integer> identityHashes = new HashSet<Integer>();
 
     public AnimatorInflaterTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     private void assertUnique(Object object) {
diff --git a/tests/tests/view/src/android/view/animation/cts/CycleInterpolatorTest.java b/tests/tests/view/src/android/view/animation/cts/CycleInterpolatorTest.java
index 3297377..3ac5950 100644
--- a/tests/tests/view/src/android/view/animation/cts/CycleInterpolatorTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/CycleInterpolatorTest.java
@@ -29,7 +29,7 @@
 import android.view.animation.Interpolator;
 import android.view.animation.Transformation;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 /**
@@ -45,7 +45,7 @@
     private static final float ALPHA_DELTA = 0.001f;
 
     public CycleInterpolatorTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/animation/cts/DecelerateInterpolatorTest.java b/tests/tests/view/src/android/view/animation/cts/DecelerateInterpolatorTest.java
index deb52dd..2400291 100644
--- a/tests/tests/view/src/android/view/animation/cts/DecelerateInterpolatorTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/DecelerateInterpolatorTest.java
@@ -16,7 +16,7 @@
 
 package android.view.animation.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.app.Activity;
@@ -45,7 +45,7 @@
     private static final long DECELERATE_ALPHA_DURATION = 2000;
 
     public DecelerateInterpolatorTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimCtsActivity.java b/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimCtsActivity.java
index bf95077..371af41 100644
--- a/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimCtsActivity.java
+++ b/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.view.animation.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.app.Activity;
 import android.database.DataSetObserver;
diff --git a/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationControllerTest.java b/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationControllerTest.java
index 54898b4..58efa0e 100644
--- a/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationControllerTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationControllerTest.java
@@ -16,7 +16,7 @@
 
 package android.view.animation.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.content.Context;
@@ -58,7 +58,7 @@
     private static final int INDEX_OF_CHILD9 = 8;
 
     public GridLayoutAnimationControllerTest() {
-        super("com.android.cts.view", GridLayoutAnimCtsActivity.class);
+        super("android.view.cts", GridLayoutAnimCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/animation/cts/LayoutAnimationControllerTest.java b/tests/tests/view/src/android/view/animation/cts/LayoutAnimationControllerTest.java
index 2f8f36d..adc4192 100644
--- a/tests/tests/view/src/android/view/animation/cts/LayoutAnimationControllerTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/LayoutAnimationControllerTest.java
@@ -16,7 +16,7 @@
 
 package android.view.animation.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.app.ListActivity;
@@ -58,7 +58,7 @@
     private static final long DEFAULT_MAX_DURATION = 2000;
 
     public LayoutAnimationControllerTest() {
-        super("com.android.cts.view", LayoutAnimCtsActivity.class);
+        super("android.view.cts", LayoutAnimCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/animation/cts/LinearInterpolatorTest.java b/tests/tests/view/src/android/view/animation/cts/LinearInterpolatorTest.java
index 28407f9..23f8608 100644
--- a/tests/tests/view/src/android/view/animation/cts/LinearInterpolatorTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/LinearInterpolatorTest.java
@@ -26,7 +26,7 @@
 import android.view.animation.LinearInterpolator;
 import android.view.animation.Transformation;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 /**
@@ -42,7 +42,7 @@
     private static final long LINEAR_ALPHA_TIME_STEP = LINEAR_ALPHA_DURATION / 5;
 
     public LinearInterpolatorTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/animation/cts/RotateAnimationTest.java b/tests/tests/view/src/android/view/animation/cts/RotateAnimationTest.java
index 958133a..afeba5c 100644
--- a/tests/tests/view/src/android/view/animation/cts/RotateAnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/RotateAnimationTest.java
@@ -28,7 +28,7 @@
 import android.view.animation.RotateAnimation;
 import android.view.animation.Transformation;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 public class RotateAnimationTest
@@ -42,7 +42,7 @@
     private static final float TO_DEGREE = 90.0f;
 
     public RotateAnimationTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/animation/cts/ScaleAnimationTest.java b/tests/tests/view/src/android/view/animation/cts/ScaleAnimationTest.java
index e17435e..dc78fa9 100644
--- a/tests/tests/view/src/android/view/animation/cts/ScaleAnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/ScaleAnimationTest.java
@@ -16,7 +16,7 @@
 
 package android.view.animation.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.content.res.XmlResourceParser;
@@ -44,7 +44,7 @@
     private AnimationTestCtsActivity mActivity;
 
     public ScaleAnimationTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/animation/cts/TranslateAnimationTest.java b/tests/tests/view/src/android/view/animation/cts/TranslateAnimationTest.java
index 94ab558..06daa72 100644
--- a/tests/tests/view/src/android/view/animation/cts/TranslateAnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/TranslateAnimationTest.java
@@ -28,7 +28,7 @@
 import android.view.animation.Transformation;
 import android.view.animation.TranslateAnimation;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 public class TranslateAnimationTest
@@ -48,7 +48,7 @@
     private static final float RELATIVE_TO_Y_DELTA = 0.4f;
 
     public TranslateAnimationTest() {
-        super("com.android.cts.view", AnimationTestCtsActivity.class);
+        super("android.view.cts", AnimationTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java b/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
index 012a13d..b25f733 100644
--- a/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
+++ b/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
@@ -23,7 +23,7 @@
 import android.test.AndroidTestCase;
 import android.view.ContextThemeWrapper;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 public class ContextThemeWrapperTest extends AndroidTestCase {
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java b/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java
index 14ab577..d2fa729 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.app.Activity;
 import android.content.Context;
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderTest.java b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
index 55c288e..6b3b784 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderTest.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
@@ -34,7 +34,7 @@
     private Button mBottomRight;
 
     public FocusFinderTest() {
-        super("com.android.cts.view", FocusFinderCtsActivity.class);
+        super("android.view.cts", FocusFinderCtsActivity.class);
     }
 
     @Override
@@ -46,6 +46,10 @@
         mTopRight = getActivity().topRightButton;
         mBottomLeft = getActivity().bottomLeftButton;
         mBottomRight = getActivity().bottomRightButton;
+        mTopLeft.setNextFocusLeftId(View.NO_ID);
+        mTopRight.setNextFocusLeftId(View.NO_ID);
+        mBottomLeft.setNextFocusLeftId(View.NO_ID);
+        mBottomRight.setNextFocusLeftId(View.NO_ID);
     }
 
     public void testGetInstance() {
@@ -169,4 +173,50 @@
         assertEquals(0, deltas[0]);
         assertEquals(-1, deltas[1]);
     }
+
+    public void testFindNextAndPrevFocusAvoidingChain() {
+        mBottomRight.setNextFocusForwardId(mBottomLeft.getId());
+        mBottomLeft.setNextFocusForwardId(mTopRight.getId());
+        // Follow the chain
+        assertNextFocus(mBottomRight, View.FOCUS_FORWARD, mBottomLeft);
+        assertNextFocus(mBottomLeft, View.FOCUS_FORWARD, mTopRight);
+        assertNextFocus(mTopRight, View.FOCUS_BACKWARD, mBottomLeft);
+        assertNextFocus(mBottomLeft, View.FOCUS_BACKWARD, mBottomRight);
+
+        // Now go to the one not in the chain
+        assertNextFocus(mTopRight, View.FOCUS_FORWARD, mTopLeft);
+        assertNextFocus(mBottomRight, View.FOCUS_BACKWARD, mTopLeft);
+
+        // Now go back to the top of the chain
+        assertNextFocus(mTopLeft, View.FOCUS_FORWARD, mBottomRight);
+        assertNextFocus(mTopLeft, View.FOCUS_BACKWARD, mTopRight);
+
+        // Now make the chain a circle -- this is the pathological case
+        mTopRight.setNextFocusForwardId(mBottomRight.getId());
+        // Fall back to the next one in a chain.
+        assertNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
+        assertNextFocus(mTopLeft, View.FOCUS_BACKWARD, mBottomRight);
+
+        //Now do branching focus changes
+        mTopRight.setNextFocusForwardId(View.NO_ID);
+        mBottomRight.setNextFocusForwardId(mTopRight.getId());
+        assertNextFocus(mBottomRight, View.FOCUS_FORWARD, mTopRight);
+        assertNextFocus(mBottomLeft, View.FOCUS_FORWARD, mTopRight);
+        // From the tail, it jumps out of the chain
+        assertNextFocus(mTopRight, View.FOCUS_FORWARD, mTopLeft);
+
+        // Back from the head of a tree goes out of the tree
+        // We don't know which is the head of the focus chain since it is branching.
+        View prevFocus1 = mFocusFinder.findNextFocus(mLayout, mBottomLeft, View.FOCUS_BACKWARD);
+        View prevFocus2 = mFocusFinder.findNextFocus(mLayout, mBottomRight, View.FOCUS_BACKWARD);
+        assertTrue(prevFocus1 == mTopLeft || prevFocus2 == mTopLeft);
+
+        // From outside, it chooses an arbitrary head of the chain
+        View nextFocus = mFocusFinder.findNextFocus(mLayout, mTopLeft, View.FOCUS_FORWARD);
+        assertTrue(nextFocus == mBottomRight || nextFocus == mBottomLeft);
+
+        // Going back from the tail of the split chain, it chooses an arbitrary head
+        nextFocus = mFocusFinder.findNextFocus(mLayout, mTopRight, View.FOCUS_BACKWARD);
+        assertTrue(nextFocus == mBottomRight || nextFocus == mBottomLeft);
+    }
 }
diff --git a/tests/tests/view/src/android/view/cts/FocusHandlingCtsActivity.java b/tests/tests/view/src/android/view/cts/FocusHandlingCtsActivity.java
index 5489e2a..86a1c9e 100644
--- a/tests/tests/view/src/android/view/cts/FocusHandlingCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/FocusHandlingCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/view/src/android/view/cts/GestureDetectorTest.java b/tests/tests/view/src/android/view/cts/GestureDetectorTest.java
index f06455d..0493088 100644
--- a/tests/tests/view/src/android/view/cts/GestureDetectorTest.java
+++ b/tests/tests/view/src/android/view/cts/GestureDetectorTest.java
@@ -45,7 +45,7 @@
     private MotionEvent mButtonPressSecondaryMotionEvent;
 
     public GestureDetectorTest() {
-        super("com.android.cts.view", GestureDetectorCtsActivity.class);
+        super("android.view.cts", GestureDetectorCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
index 00b9fe9..9208b13 100644
--- a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
+++ b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 import android.view.cts.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -210,7 +210,7 @@
 
     public void testInflate() {
         View view = mLayoutInflater.inflate(
-                com.android.cts.view.R.layout.inflater_layout, null);
+                android.view.cts.R.layout.inflater_layout, null);
         assertNotNull(view);
         view = null;
         try {
@@ -385,7 +385,7 @@
 
     public void testInflateTags() {
         final View view = mLayoutInflater.inflate(
-                com.android.cts.view.R.layout.inflater_layout_tags, null);
+                android.view.cts.R.layout.inflater_layout_tags, null);
         assertNotNull(view);
 
         checkViewTag(view, R.id.viewlayout_root, R.id.tag_viewlayout_root, R.string.tag1);
diff --git a/tests/tests/view/src/android/view/cts/MenuInflaterTest.java b/tests/tests/view/src/android/view/cts/MenuInflaterTest.java
index 7e3517f..9ced9c7 100644
--- a/tests/tests/view/src/android/view/cts/MenuInflaterTest.java
+++ b/tests/tests/view/src/android/view/cts/MenuInflaterTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.app.Activity;
 import android.content.res.Resources;
@@ -40,7 +40,7 @@
     private Activity mActivity;
 
     public MenuInflaterTest() {
-        super("com.android.cts.view", MenuInflaterCtsActivity.class);
+        super("android.view.cts", MenuInflaterCtsActivity.class);
     }
 
     @Override
@@ -67,7 +67,7 @@
             mMenuInflater = mActivity.getMenuInflater();
         }
 
-        mMenuInflater.inflate(com.android.cts.view.R.menu.browser, menu);
+        mMenuInflater.inflate(android.view.cts.R.menu.browser, menu);
         assertNotNull(menu);
         assertEquals(1, menu.size());
 
@@ -78,7 +78,7 @@
         }
 
         try {
-            mMenuInflater.inflate(com.android.cts.view.R.menu.browser, null);
+            mMenuInflater.inflate(android.view.cts.R.menu.browser, null);
             fail("should throw NullPointerException");
         } catch (NullPointerException e) {
         }
@@ -107,7 +107,7 @@
 
         // the titles and icons
         menu = createMenu(mActivity);
-        mMenuInflater.inflate(com.android.cts.view.R.menu.title_icon, menu);
+        mMenuInflater.inflate(android.view.cts.R.menu.title_icon, menu);
 
         assertEquals("Start", menu.findItem(R.id.start).getTitle());
         assertIconUsingDrawableRes((BitmapDrawable) menu.findItem(R.id.start).getIcon(),
@@ -123,7 +123,7 @@
 
         // the orders and categories
         menu = createMenu(mActivity);
-        mMenuInflater.inflate(com.android.cts.view.R.menu.category_order, menu);
+        mMenuInflater.inflate(android.view.cts.R.menu.category_order, menu);
         // default category
         assertEquals(R.id.most_used_items, menu.findItem(R.id.first_most_item).getGroupId());
         assertEquals(1, menu.findItem(R.id.first_most_item).getOrder());
@@ -147,7 +147,7 @@
 
         // the checkables
         menu = createMenu(mActivity);
-        mMenuInflater.inflate(com.android.cts.view.R.menu.checkable, menu);
+        mMenuInflater.inflate(android.view.cts.R.menu.checkable, menu);
         // noncheckables
         assertEquals(R.id.noncheckable_group,
                 menu.findItem(R.id.noncheckable_item_1).getGroupId());
diff --git a/tests/tests/view/src/android/view/cts/ScaleGestureDetectorTest.java b/tests/tests/view/src/android/view/cts/ScaleGestureDetectorTest.java
index b8ba200..b56d67e 100644
--- a/tests/tests/view/src/android/view/cts/ScaleGestureDetectorTest.java
+++ b/tests/tests/view/src/android/view/cts/ScaleGestureDetectorTest.java
@@ -32,7 +32,7 @@
     private Context mContext;
 
     public ScaleGestureDetectorTest() {
-        super("com.android.cts.view", ScaleGestureDetectorCtsActivity.class);
+        super("android.view.cts", ScaleGestureDetectorCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/cts/SearchEventActivity.java b/tests/tests/view/src/android/view/cts/SearchEventActivity.java
index 6cc8c85..292ecb9 100644
--- a/tests/tests/view/src/android/view/cts/SearchEventActivity.java
+++ b/tests/tests/view/src/android/view/cts/SearchEventActivity.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/view/src/android/view/cts/SearchEventTest.java b/tests/tests/view/src/android/view/cts/SearchEventTest.java
index 4df52a1..629b3ab 100644
--- a/tests/tests/view/src/android/view/cts/SearchEventTest.java
+++ b/tests/tests/view/src/android/view/cts/SearchEventTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
diff --git a/tests/tests/view/src/android/view/cts/SurfaceViewTest.java b/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
index a84653d..aa97ffd 100644
--- a/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
+++ b/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
@@ -37,7 +37,7 @@
     private MockSurfaceView mMockSurfaceView;
 
     public SurfaceViewTest() {
-        super("com.android.cts.view", SurfaceViewCtsActivity.class);
+        super("android.view.cts", SurfaceViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/cts/TouchDelegateTest.java b/tests/tests/view/src/android/view/cts/TouchDelegateTest.java
index 34d96bc..47fe6c6 100644
--- a/tests/tests/view/src/android/view/cts/TouchDelegateTest.java
+++ b/tests/tests/view/src/android/view/cts/TouchDelegateTest.java
@@ -44,7 +44,7 @@
     private Exception mException;
 
     public TouchDelegateTest() {
-        super("com.android.cts.view", MockActivity.class);
+        super("android.view.cts", MockActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/cts/UsingViewsCtsActivity.java b/tests/tests/view/src/android/view/cts/UsingViewsCtsActivity.java
index a5ccbcd..a9361a3 100644
--- a/tests/tests/view/src/android/view/cts/UsingViewsCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/UsingViewsCtsActivity.java
@@ -18,7 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 /**
  * A simple activity to test "Using Views"
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupCtsActivity.java b/tests/tests/view/src/android/view/cts/ViewGroupCtsActivity.java
index 880a450..de1db19 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupCtsActivity.java
@@ -35,8 +35,8 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(com.android.cts.view.R.layout.viewgrouptest_stub);
-        TextView textView = (TextView)findViewById(com.android.cts.view.R.id.viewgrouptest_stub);
+        setContentView(android.view.cts.R.layout.viewgrouptest_stub);
+        TextView textView = (TextView)findViewById(android.view.cts.R.id.viewgrouptest_stub);
         textView.setText("test");
     }
 
@@ -49,7 +49,7 @@
             mHandler.postDelayed(new Runnable() {
                 public void run() {
                     MockLinearLayout mll =
-                        (MockLinearLayout) findViewById(com.android.cts.view.R.id.
+                        (MockLinearLayout) findViewById(android.view.cts.R.id.
                                                                         mocklinearlayout);
                     if (!mll.mIsInvalidateChildInParentCalled) {
                         fail();
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupTest.java b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
index 7fc5579..1b18fe9 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
@@ -59,6 +59,7 @@
 import android.view.animation.Animation.AnimationListener;
 import android.widget.TextView;
 
+import java.lang.IndexOutOfBoundsException;
 import java.util.ArrayList;
 
 public class ViewGroupTest extends InstrumentationTestCase implements CTSResult{
@@ -338,23 +339,23 @@
 
         Canvas canvas = new Canvas();
         MockViewGroup vg = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
-        son.setAnimation(new MockAnimation());
-        vg.addView(son);
+        MockViewGroup child = new MockViewGroup(mContext);
+        child.setAnimation(new MockAnimation());
+        vg.addView(child);
         assertEquals(1, vg.getChildCount());
 
-        assertNotNull(son.getAnimation());
+        assertNotNull(child.getAnimation());
         vg.dispatchDraw(canvas);
         assertEquals(1, vg.drawChildCalledTime);
 
-        son.setAnimation(new MockAnimation());
+        child.setAnimation(new MockAnimation());
         vg.removeAllViewsInLayout();
 
         vg.drawChildCalledTime = 0;
         vg.dispatchDraw(canvas);
         assertEquals(1, vg.drawChildCalledTime);
 
-        son.setAnimation(new MockAnimation());
+        child.setAnimation(new MockAnimation());
         vg.clearDisappearingChildren();
 
         vg.drawChildCalledTime = 0;
@@ -683,11 +684,11 @@
 
     public void testFocusableViewAvailable() {
         MockViewGroup vg = new MockViewGroup(mContext);
-        MockView son = new MockView(mContext);
-        vg.addView(son);
+        MockView child = new MockView(mContext);
+        vg.addView(child);
 
-        son.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
-        son.focusableViewAvailable(vg);
+        child.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+        child.focusableViewAvailable(vg);
 
         assertTrue(vg.isFocusableViewAvailable);
     }
@@ -695,11 +696,11 @@
     public void testFocusSearch() {
         MockViewGroup vg = new MockViewGroup(mContext);
         MockTextView textView = new MockTextView(mContext);
-        MockView son = new MockView(mContext);
-        vg.addView(son);
-        son.addView(textView);
-        assertNotNull(son.focusSearch(textView, 1));
-        assertSame(textView, son.focusSearch(textView, 1));
+        MockView child = new MockView(mContext);
+        vg.addView(child);
+        child.addView(textView);
+        assertNotNull(child.focusSearch(textView, 1));
+        assertSame(textView, child.focusSearch(textView, 1));
     }
 
     public void testGatherTransparentRegion() {
@@ -726,7 +727,7 @@
     public void testGenerateLayoutParamsWithParaAttributeSet() throws Exception{
         MockViewGroup vg = new MockViewGroup(mContext);
         XmlResourceParser set = mContext.getResources().getLayout(
-                com.android.cts.view.R.layout.abslistview_layout);
+                android.view.cts.R.layout.abslistview_layout);
         XmlUtils.beginDocument(set, "ViewGroup_Layout");
         LayoutParams lp = vg.generateLayoutParams(set);
         assertNotNull(lp);
@@ -738,7 +739,10 @@
         MockViewGroup vg = new MockViewGroup(mContext);
         LayoutParams p = new LayoutParams(LayoutParams.WRAP_CONTENT,
                 LayoutParams.MATCH_PARENT);
-        assertSame(p, vg.generateLayoutParams(p));
+        LayoutParams generatedParams = vg.generateLayoutParams(p);
+        assertEquals(generatedParams.getClass(), p.getClass());
+        assertEquals(p.width, generatedParams.width);
+        assertEquals(p.height, generatedParams.height);
     }
 
     public void testGetChildDrawingOrder() {
@@ -924,18 +928,18 @@
         final int width = 100;
         final int height = 200;
         MockViewGroup vg = new MockViewGroup(mContext);
-        MockView son = new MockView(mContext);
-        son.setLayoutParams(new LayoutParams(width, height));
-        son.forceLayout();
-        vg.addView(son);
+        MockView child = new MockView(mContext);
+        child.setLayoutParams(new LayoutParams(width, height));
+        child.forceLayout();
+        vg.addView(child);
 
         final int parentWidthMeasureSpec = 1;
         final int parentHeightMeasureSpec = 2;
-        vg.measureChild(son, parentWidthMeasureSpec, parentHeightMeasureSpec);
+        vg.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec);
         assertEquals(ViewGroup.getChildMeasureSpec(parentWidthMeasureSpec, 0, width),
-                son.mWidthMeasureSpec);
+                child.mWidthMeasureSpec);
         assertEquals(ViewGroup.getChildMeasureSpec(parentHeightMeasureSpec, 0, height),
-                son.mHeightMeasureSpec);
+                child.mHeightMeasureSpec);
     }
 
     public void testMeasureChildren() {
@@ -966,24 +970,24 @@
         final int parentHeightMeasureSpec = 3;
         final int heightUsed = 4;
         MockViewGroup vg = new MockViewGroup(mContext);
-        MockView son = new MockView(mContext);
+        MockView child = new MockView(mContext);
 
-        vg.addView(son);
-        son.setLayoutParams(new ViewGroup.LayoutParams(width, height));
+        vg.addView(child);
+        child.setLayoutParams(new ViewGroup.LayoutParams(width, height));
         try {
-            vg.measureChildWithMargins(son, parentWidthMeasureSpec, widthUsed,
+            vg.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
                     parentHeightMeasureSpec, heightUsed);
             fail("measureChildWithMargins should throw out class cast exception");
         } catch (RuntimeException e) {
         }
-        son.setLayoutParams(new ViewGroup.MarginLayoutParams(width, height));
+        child.setLayoutParams(new ViewGroup.MarginLayoutParams(width, height));
 
-        vg.measureChildWithMargins(son, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec,
+        vg.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec,
                 heightUsed);
         assertEquals(ViewGroup.getChildMeasureSpec(parentWidthMeasureSpec, parentHeightMeasureSpec,
-                width), son.mWidthMeasureSpec);
+                width), child.mWidthMeasureSpec);
         assertEquals(ViewGroup.getChildMeasureSpec(widthUsed, heightUsed, height),
-                son.mHeightMeasureSpec);
+                child.mHeightMeasureSpec);
     }
 
     public void testOffsetDescendantRectToMyCoords() {
@@ -1032,16 +1036,16 @@
 
     public void testOnAnimationEnd() {
         // this function is a call back function it should be tested in ViewGroup#drawChild.
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
-        son.setAnimation(new MockAnimation());
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child = new MockViewGroup(mContext);
+        child.setAnimation(new MockAnimation());
         // this call will make mPrivateFlags |= ANIMATION_STARTED;
-        son.onAnimationStart();
-        father.addView(son);
+        child.onAnimationStart();
+        parent.addView(child);
 
         MockCanvas canvas = new MockCanvas();
-        assertFalse(father.drawChild(canvas, son, 100));
-        assertTrue(son.isOnAnimationEndCalled);
+        assertFalse(parent.drawChild(canvas, child, 100));
+        assertTrue(child.isOnAnimationEndCalled);
     }
 
     private class MockAnimation extends Animation {
@@ -1062,22 +1066,22 @@
 
     public void testOnAnimationStart() {
         // This is a call back method. It should be tested in ViewGroup#drawChild.
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child = new MockViewGroup(mContext);
 
-        father.addView(son);
+        parent.addView(child);
 
         MockCanvas canvas = new MockCanvas();
         try {
-            assertFalse(father.drawChild(canvas, son, 100));
-            assertFalse(son.isOnAnimationStartCalled);
+            assertFalse(parent.drawChild(canvas, child, 100));
+            assertFalse(child.isOnAnimationStartCalled);
         } catch (Exception e) {
             // expected
         }
 
-        son.setAnimation(new MockAnimation());
-        assertFalse(father.drawChild(canvas, son, 100));
-        assertTrue(son.isOnAnimationStartCalled);
+        child.setAnimation(new MockAnimation());
+        assertFalse(parent.drawChild(canvas, child, 100));
+        assertTrue(child.isOnAnimationStartCalled);
     }
 
     public void testOnCreateDrawableState() {
@@ -1132,35 +1136,35 @@
     }
 
     public void testRemoveAllViewsInLayout() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child = new MockViewGroup(mContext);
         MockTextView textView = new MockTextView(mContext);
 
-        assertEquals(0, father.getChildCount());
+        assertEquals(0, parent.getChildCount());
 
-        son.addView(textView);
-        father.addView(son);
-        assertEquals(1, father.getChildCount());
+        child.addView(textView);
+        parent.addView(child);
+        assertEquals(1, parent.getChildCount());
 
-        father.removeAllViewsInLayout();
-        assertEquals(0, father.getChildCount());
-        assertEquals(1, son.getChildCount());
-        assertNull(son.getParent());
-        assertSame(son, textView.getParent());
+        parent.removeAllViewsInLayout();
+        assertEquals(0, parent.getChildCount());
+        assertEquals(1, child.getChildCount());
+        assertNull(child.getParent());
+        assertSame(child, textView.getParent());
     }
 
     public void testRemoveDetachedView() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son1 = new MockViewGroup(mContext);
-        MockViewGroup son2 = new MockViewGroup(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child1 = new MockViewGroup(mContext);
+        MockViewGroup child2 = new MockViewGroup(mContext);
         MockOnHierarchyChangeListener listener = new MockOnHierarchyChangeListener();
-        father.setOnHierarchyChangeListener(listener);
-        father.addView(son1);
-        father.addView(son2);
+        parent.setOnHierarchyChangeListener(listener);
+        parent.addView(child1);
+        parent.addView(child2);
 
-        father.removeDetachedView(son1, false);
-        assertSame(father, listener.sParent);
-        assertSame(son1, listener.sChild);
+        parent.removeDetachedView(child1, false);
+        assertSame(parent, listener.sParent);
+        assertSame(child1, listener.sChild);
     }
 
     static class MockOnHierarchyChangeListener implements OnHierarchyChangeListener {
@@ -1178,93 +1182,123 @@
     }
 
     public void testRemoveView() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child = new MockViewGroup(mContext);
 
-        assertEquals(0, father.getChildCount());
+        assertEquals(0, parent.getChildCount());
 
-        father.addView(son);
-        assertEquals(1, father.getChildCount());
+        parent.addView(child);
+        assertEquals(1, parent.getChildCount());
 
-        father.removeView(son);
-        assertEquals(0, father.getChildCount());
-        assertNull(son.getParent());
+        parent.removeView(child);
+        assertEquals(0, parent.getChildCount());
+        assertNull(child.getParent());
     }
 
     public void testRemoveViewAt() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child = new MockViewGroup(mContext);
 
-        assertEquals(0, father.getChildCount());
+        assertEquals(0, parent.getChildCount());
 
-        father.addView(son);
-        assertEquals(1, father.getChildCount());
+        parent.addView(child);
+        assertEquals(1, parent.getChildCount());
 
         try {
-            father.removeViewAt(2);
+            parent.removeViewAt(2);
             fail("should throw out null pointer exception");
         } catch (RuntimeException e) {
             // expected
         }
-        assertEquals(1, father.getChildCount());
+        assertEquals(1, parent.getChildCount());
 
-        father.removeViewAt(0);
-        assertEquals(0, father.getChildCount());
-        assertNull(son.getParent());
+        parent.removeViewAt(0);
+        assertEquals(0, parent.getChildCount());
+        assertNull(child.getParent());
     }
 
     public void testRemoveViewInLayout() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child = new MockViewGroup(mContext);
 
-        assertEquals(0, father.getChildCount());
+        assertEquals(0, parent.getChildCount());
 
-        father.addView(son);
-        assertEquals(1, father.getChildCount());
+        parent.addView(child);
+        assertEquals(1, parent.getChildCount());
 
-        father.removeViewInLayout(son);
-        assertEquals(0, father.getChildCount());
-        assertNull(son.getParent());
+        parent.removeViewInLayout(child);
+        assertEquals(0, parent.getChildCount());
+        assertNull(child.getParent());
     }
 
     public void testRemoveViews() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son1 = new MockViewGroup(mContext);
-        MockViewGroup son2 = new MockViewGroup(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child1 = new MockViewGroup(mContext);
+        MockViewGroup child2 = new MockViewGroup(mContext);
 
-        assertEquals(0, father.getChildCount());
+        assertEquals(0, parent.getChildCount());
+        parent.addView(child1);
+        parent.addView(child2);
+        assertEquals(2, parent.getChildCount());
 
-        father.addView(son1);
-        father.addView(son2);
-        assertEquals(2, father.getChildCount());
+        try {
+            parent.removeViews(-1, 1); // negative begin
+            fail("should fail with IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {}
 
-        father.removeViews(0, 1);
-        assertEquals(1, father.getChildCount());
-        assertNull(son1.getParent());
+        try {
+            parent.removeViews(0, -1); // negative count
+            fail("should fail with IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {}
 
-        father.removeViews(0, 1);
-        assertEquals(0, father.getChildCount());
-        assertNull(son2.getParent());
+        try {
+            parent.removeViews(1, 2); // past end
+            fail("should fail with IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {}
+        assertEquals(2, parent.getChildCount()); // child list unmodified
+
+        parent.removeViews(0, 1);
+        assertEquals(1, parent.getChildCount());
+        assertNull(child1.getParent());
+
+        parent.removeViews(0, 1);
+        assertEquals(0, parent.getChildCount());
+        assertNull(child2.getParent());
     }
 
     public void testRemoveViewsInLayout() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son1 = new MockViewGroup(mContext);
-        MockViewGroup son2 = new MockViewGroup(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child1 = new MockViewGroup(mContext);
+        MockViewGroup child2 = new MockViewGroup(mContext);
 
-        assertEquals(0, father.getChildCount());
+        assertEquals(0, parent.getChildCount());
+        parent.addView(child1);
+        parent.addView(child2);
+        assertEquals(2, parent.getChildCount());
 
-        father.addView(son1);
-        father.addView(son2);
-        assertEquals(2, father.getChildCount());
+        try {
+            parent.removeViewsInLayout(-1, 1); // negative begin
+            fail("should fail with IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {}
 
-        father.removeViewsInLayout(0, 1);
-        assertEquals(1, father.getChildCount());
-        assertNull(son1.getParent());
+        try {
+            parent.removeViewsInLayout(0, -1); // negative count
+            fail("should fail with IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {}
 
-        father.removeViewsInLayout(0, 1);
-        assertEquals(0, father.getChildCount());
-        assertNull(son2.getParent());
+        try {
+            parent.removeViewsInLayout(1, 2); // past end
+            fail("should fail with IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {}
+        assertEquals(2, parent.getChildCount()); // child list unmodified
+
+        parent.removeViewsInLayout(0, 1);
+        assertEquals(1, parent.getChildCount());
+        assertNull(child1.getParent());
+
+        parent.removeViewsInLayout(0, 1);
+        assertEquals(0, parent.getChildCount());
+        assertNull(child2.getParent());
     }
 
     public void testRequestChildFocus() {
@@ -1286,13 +1320,13 @@
     }
 
     public void testRequestDisallowInterceptTouchEvent() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockView son = new MockView(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockView child = new MockView(mContext);
 
-        father.addView(son);
-        son.requestDisallowInterceptTouchEvent(true);
-        son.requestDisallowInterceptTouchEvent(false);
-        assertTrue(father.isRequestDisallowInterceptTouchEventCalled);
+        parent.addView(child);
+        child.requestDisallowInterceptTouchEvent(true);
+        child.requestDisallowInterceptTouchEvent(false);
+        assertTrue(parent.isRequestDisallowInterceptTouchEventCalled);
     }
 
     public void testRequestFocus() {
@@ -1303,13 +1337,13 @@
     }
 
     public void testRequestTransparentRegion() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockView son1 = new MockView(mContext);
-        MockView son2 = new MockView(mContext);
-        son1.addView(son2);
-        father.addView(son1);
-        son1.requestTransparentRegion(son2);
-        assertTrue(father.isRequestTransparentRegionCalled);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockView child1 = new MockView(mContext);
+        MockView child2 = new MockView(mContext);
+        child1.addView(child2);
+        parent.addView(child1);
+        child1.requestTransparentRegion(child2);
+        assertTrue(parent.isRequestTransparentRegionCalled);
     }
 
     public void testScheduleLayoutAnimation() {
@@ -1476,15 +1510,15 @@
     }
 
     public void testSetOnHierarchyChangeListener() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child = new MockViewGroup(mContext);
         MockOnHierarchyChangeListener listener = new MockOnHierarchyChangeListener();
-        father.setOnHierarchyChangeListener(listener);
-        father.addView(son);
+        parent.setOnHierarchyChangeListener(listener);
+        parent.addView(child);
 
-        father.removeDetachedView(son, false);
-        assertSame(father, listener.sParent);
-        assertSame(son, listener.sChild);
+        parent.removeDetachedView(child, false);
+        assertSame(parent, listener.sParent);
+        assertSame(child, listener.sChild);
     }
 
     public void testSetPadding() {
@@ -1595,12 +1629,12 @@
     }
 
     public void testShowContextMenuForChild() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
-        father.addView(son);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child = new MockViewGroup(mContext);
+        parent.addView(child);
 
-        son.showContextMenuForChild(null);
-        assertTrue(father.isShowContextMenuForChildCalled);
+        child.showContextMenuForChild(null);
+        assertTrue(parent.isShowContextMenuForChildCalled);
     }
 
     public void testStartLayoutAnimation() {
@@ -1616,24 +1650,24 @@
     }
 
     public void testUpdateViewLayout() {
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child = new MockViewGroup(mContext);
 
-        father.addView(son);
+        parent.addView(child);
         LayoutParams param = new LayoutParams(100, 200);
-        father.updateViewLayout(son, param);
-        assertEquals(param.width, son.getLayoutParams().width);
-        assertEquals(param.height, son.getLayoutParams().height);
+        parent.updateViewLayout(child, param);
+        assertEquals(param.width, child.getLayoutParams().width);
+        assertEquals(param.height, child.getLayoutParams().height);
     }
 
     public void testDebug() {
         final int EXPECTED = 100;
-        MockViewGroup father = new MockViewGroup(mContext);
-        MockViewGroup son = new MockViewGroup(mContext);
-        father.addView(son);
+        MockViewGroup parent = new MockViewGroup(mContext);
+        MockViewGroup child = new MockViewGroup(mContext);
+        parent.addView(child);
 
-        father.debug(EXPECTED);
-        assertEquals(EXPECTED + 1, son.debugDepth);
+        parent.debug(EXPECTED);
+        assertEquals(EXPECTED + 1, child.debugDepth);
     }
 
     public void testDispatchKeyEventPreIme() {
diff --git a/tests/tests/view/src/android/view/cts/ViewGroup_LayoutParamsTest.java b/tests/tests/view/src/android/view/cts/ViewGroup_LayoutParamsTest.java
index 5dadffd..7476ba6 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroup_LayoutParamsTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroup_LayoutParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import org.xmlpull.v1.XmlPullParserException;
 
diff --git a/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java b/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
index e53cba2..0420a4a 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.content.Context;
 import android.content.res.XmlResourceParser;
diff --git a/tests/tests/view/src/android/view/cts/ViewLayoutPositionTestCtsActivity.java b/tests/tests/view/src/android/view/cts/ViewLayoutPositionTestCtsActivity.java
index 69dc70f..41f3e33 100644
--- a/tests/tests/view/src/android/view/cts/ViewLayoutPositionTestCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/ViewLayoutPositionTestCtsActivity.java
@@ -18,7 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 public class ViewLayoutPositionTestCtsActivity extends Activity {
     @Override
diff --git a/tests/tests/view/src/android/view/cts/ViewStubCtsActivity.java b/tests/tests/view/src/android/view/cts/ViewStubCtsActivity.java
index d2f2a4f..4268837 100644
--- a/tests/tests/view/src/android/view/cts/ViewStubCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/ViewStubCtsActivity.java
@@ -18,7 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 public class ViewStubCtsActivity extends Activity {
     @Override
diff --git a/tests/tests/view/src/android/view/cts/ViewStubTest.java b/tests/tests/view/src/android/view/cts/ViewStubTest.java
index c9cd44b..bdb988d 100644
--- a/tests/tests/view/src/android/view/cts/ViewStubTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewStubTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -40,7 +40,7 @@
     private Activity mActivity;
 
     public ViewStubTest() {
-        super("com.android.cts.view", ViewStubCtsActivity.class);
+        super("android.view.cts", ViewStubCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 2c5b30a..549466a 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -16,7 +16,8 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.ViewTreeObserver;
+import android.view.cts.R;
 import com.android.internal.view.menu.ContextMenuBuilder;
 
 import android.content.Context;
@@ -45,6 +46,7 @@
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 import android.util.Xml;
 import android.view.ActionMode;
@@ -84,9 +86,12 @@
 import android.widget.LinearLayout;
 import android.widget.ListView;
 
+import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test {@link View}.
@@ -146,6 +151,37 @@
         }
     }
 
+    // Test that validates that Views can be constructed on a thread that
+    // does not have a Looper. Necessary for async inflation
+    private Pair<Class<?>, Throwable> sCtorException = null;
+    public void testConstructor2() throws Exception {
+        final Object[] args = new Object[] { mActivity, null };
+        final CountDownLatch latch = new CountDownLatch(1);
+        sCtorException = null;
+        new Thread() {
+            public void run() {
+                final Class<?>[] ctorSignature = new Class[] {
+                        Context.class, AttributeSet.class};
+                for (Class<?> clazz : ASYNC_INFLATE_VIEWS) {
+                    try {
+                        Constructor<?> constructor = clazz.getConstructor(ctorSignature);
+                        constructor.setAccessible(true);
+                        constructor.newInstance(args);
+                    } catch (Throwable t) {
+                        sCtorException = new Pair<Class<?>, Throwable>(clazz, t);
+                        break;
+                    }
+                }
+                latch.countDown();
+            }
+        }.start();
+        latch.await();
+        if (sCtorException != null) {
+            throw new AssertionError("Failed to inflate "
+                    + sCtorException.first.getName(), sCtorException.second);
+        }
+    }
+
     public void testGetContext() {
         View view = new View(mActivity);
         assertSame(mActivity, view.getContext());
@@ -2230,6 +2266,71 @@
         assertTrue(listener.hasOnClick());
     }
 
+    private void checkBounds(final ViewGroup viewGroup, final View view,
+            final CountDownLatch countDownLatch, final int left, final int top,
+            final int width, final int height) {
+        viewGroup.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+            @Override
+            public boolean onPreDraw() {
+                assertEquals(left, view.getLeft());
+                assertEquals(top, view.getTop());
+                assertEquals(width, view.getWidth());
+                assertEquals(height, view.getHeight());
+                countDownLatch.countDown();
+                viewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
+                return true;
+            }
+        });
+    }
+
+    public void testAddRemoveAffectsWrapContentLayout() throws Throwable {
+        final int childWidth = 100;
+        final int childHeight = 200;
+        final int parentHeight = 400;
+        final MockLinearLayout parent = new MockLinearLayout(mActivity);
+        ViewGroup.LayoutParams parentParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, parentHeight);
+        parent.setLayoutParams(parentParams);
+        final MockView child = new MockView(mActivity);
+        child.setBackgroundColor(Color.GREEN);
+        ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
+        child.setLayoutParams(childParams);
+        final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
+
+        // Idea:
+        // Add the wrap_content parent view to the hierarchy (removing other views as they
+        // are not needed), test that parent is 0xparentHeight
+        // Add the child view to the parent, test that parent has same width as child
+        // Remove the child view from the parent, test that parent is 0xparentHeight
+        final CountDownLatch countDownLatch1 = new CountDownLatch(1);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                viewGroup.removeAllViews();
+                viewGroup.addView(parent);
+                checkBounds(viewGroup, parent, countDownLatch1, 0, 0, 0, parentHeight);
+            }
+        });
+        countDownLatch1.await(500, TimeUnit.MILLISECONDS);
+
+        final CountDownLatch countDownLatch2 = new CountDownLatch(1);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                parent.addView(child);
+                checkBounds(viewGroup, parent, countDownLatch2, 0, 0, childWidth, parentHeight);
+            }
+        });
+        countDownLatch2.await(500, TimeUnit.MILLISECONDS);
+
+        final CountDownLatch countDownLatch3 = new CountDownLatch(1);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                parent.removeView(child);
+                checkBounds(viewGroup, parent, countDownLatch3, 0, 0, 0, parentHeight);
+            }
+        });
+        countDownLatch3.await(500, TimeUnit.MILLISECONDS);
+    }
+
     @UiThreadTest
     public void testDispatchKeyEvent() {
         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
@@ -2537,7 +2638,7 @@
         assertFalse(view.hasCalledOnWindowFocusChanged());
         assertFalse(view.hasCalledDispatchWindowFocusChanged());
 
-        CtsActivity activity = launchActivity("com.android.cts.view", CtsActivity.class, null);
+        CtsActivity activity = launchActivity("android.view.cts", CtsActivity.class, null);
 
         // Wait until the window lost focus.
         new PollingCheck(TIMEOUT_DELTA) {
@@ -4095,4 +4196,75 @@
             hasRun = true;
         }
     }
+
+    private static final Class<?> ASYNC_INFLATE_VIEWS[] = {
+        android.app.FragmentBreadCrumbs.class,
+// DISABLED because it doesn't have a AppWidgetHostView(Context, AttributeSet)
+// constructor, so it's not inflate-able
+//        android.appwidget.AppWidgetHostView.class,
+        android.gesture.GestureOverlayView.class,
+        android.inputmethodservice.ExtractEditText.class,
+        android.inputmethodservice.KeyboardView.class,
+//        android.media.tv.TvView.class,
+//        android.opengl.GLSurfaceView.class,
+//        android.view.SurfaceView.class,
+        android.view.TextureView.class,
+        android.view.ViewStub.class,
+//        android.webkit.WebView.class,
+        android.widget.AbsoluteLayout.class,
+        android.widget.AdapterViewFlipper.class,
+        android.widget.AnalogClock.class,
+        android.widget.AutoCompleteTextView.class,
+        android.widget.Button.class,
+        android.widget.CalendarView.class,
+        android.widget.CheckBox.class,
+        android.widget.CheckedTextView.class,
+        android.widget.Chronometer.class,
+        android.widget.DatePicker.class,
+        android.widget.DialerFilter.class,
+        android.widget.DigitalClock.class,
+        android.widget.EditText.class,
+        android.widget.ExpandableListView.class,
+        android.widget.FrameLayout.class,
+        android.widget.Gallery.class,
+        android.widget.GridView.class,
+        android.widget.HorizontalScrollView.class,
+        android.widget.ImageButton.class,
+        android.widget.ImageSwitcher.class,
+        android.widget.ImageView.class,
+        android.widget.LinearLayout.class,
+        android.widget.ListView.class,
+        android.widget.MediaController.class,
+        android.widget.MultiAutoCompleteTextView.class,
+        android.widget.NumberPicker.class,
+        android.widget.ProgressBar.class,
+        android.widget.QuickContactBadge.class,
+        android.widget.RadioButton.class,
+        android.widget.RadioGroup.class,
+        android.widget.RatingBar.class,
+        android.widget.RelativeLayout.class,
+        android.widget.ScrollView.class,
+        android.widget.SeekBar.class,
+// DISABLED because it has required attributes
+//        android.widget.SlidingDrawer.class,
+        android.widget.Spinner.class,
+        android.widget.StackView.class,
+        android.widget.Switch.class,
+        android.widget.TabHost.class,
+        android.widget.TabWidget.class,
+        android.widget.TableLayout.class,
+        android.widget.TableRow.class,
+        android.widget.TextClock.class,
+        android.widget.TextSwitcher.class,
+        android.widget.TextView.class,
+        android.widget.TimePicker.class,
+        android.widget.ToggleButton.class,
+        android.widget.TwoLineListItem.class,
+//        android.widget.VideoView.class,
+        android.widget.ViewAnimator.class,
+        android.widget.ViewFlipper.class,
+        android.widget.ViewSwitcher.class,
+        android.widget.ZoomButton.class,
+        android.widget.ZoomControls.class,
+    };
 }
diff --git a/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java b/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
index 01215bc..bbe6ccc 100644
--- a/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
@@ -20,7 +20,7 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.util.Log;
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 public class ViewTestCtsActivity extends Activity {
     private boolean mHasWindowFocus = false;
diff --git a/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java b/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
index 7071808..b799e76 100644
--- a/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.app.Activity;
 import android.app.Instrumentation;
diff --git a/tests/tests/view/src/android/view/cts/View_AnimationTest.java b/tests/tests/view/src/android/view/cts/View_AnimationTest.java
index 64bb2f7..07abb6f 100644
--- a/tests/tests/view/src/android/view/cts/View_AnimationTest.java
+++ b/tests/tests/view/src/android/view/cts/View_AnimationTest.java
@@ -24,7 +24,7 @@
 import android.view.animation.TranslateAnimation;
 import android.view.animation.cts.AnimationTestUtils;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 /**
@@ -40,7 +40,7 @@
     private TranslateAnimation mAnimation;
 
     public View_AnimationTest() {
-        super("com.android.cts.view", ViewTestCtsActivity.class);
+        super("android.view.cts", ViewTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
index 97992ee..564620e 100644
--- a/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
+++ b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.app.Activity;
@@ -28,7 +28,7 @@
 public class View_FocusHandlingTest
         extends ActivityInstrumentationTestCase2<FocusHandlingCtsActivity> {
     public View_FocusHandlingTest() {
-        super("com.android.cts.view", FocusHandlingCtsActivity.class);
+        super("android.view.cts", FocusHandlingCtsActivity.class);
     }
 
     @UiThreadTest
diff --git a/tests/tests/view/src/android/view/cts/View_IdsTest.java b/tests/tests/view/src/android/view/cts/View_IdsTest.java
index e65ccf5..4dd00d6 100644
--- a/tests/tests/view/src/android/view/cts/View_IdsTest.java
+++ b/tests/tests/view/src/android/view/cts/View_IdsTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.app.Activity;
@@ -29,7 +29,7 @@
 
 public class View_IdsTest extends ActivityInstrumentationTestCase2<UsingViewsCtsActivity> {
     public View_IdsTest() {
-        super("com.android.cts.view", UsingViewsCtsActivity.class);
+        super("android.view.cts", UsingViewsCtsActivity.class);
     }
 
     @UiThreadTest
diff --git a/tests/tests/view/src/android/view/cts/View_LayoutPositionTest.java b/tests/tests/view/src/android/view/cts/View_LayoutPositionTest.java
index 3938607..53514dc 100644
--- a/tests/tests/view/src/android/view/cts/View_LayoutPositionTest.java
+++ b/tests/tests/view/src/android/view/cts/View_LayoutPositionTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.app.Activity;
@@ -36,7 +36,7 @@
     private Activity mActivity;
 
     public View_LayoutPositionTest() {
-        super("com.android.cts.view", ViewLayoutPositionTestCtsActivity.class);
+        super("android.view.cts", ViewLayoutPositionTestCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java b/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java
index f6d067d..413c356 100644
--- a/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java
+++ b/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.app.Activity;
@@ -78,7 +78,7 @@
     private TextView mWarningTextView;
 
     public View_UsingViewsTest() {
-        super("com.android.cts.view", UsingViewsCtsActivity.class);
+        super("android.view.cts", UsingViewsCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/cts/WindowCtsActivity.java b/tests/tests/view/src/android/view/cts/WindowCtsActivity.java
index 8af808c..3cfcc96 100644
--- a/tests/tests/view/src/android/view/cts/WindowCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/WindowCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/view/src/android/view/cts/WindowTest.java b/tests/tests/view/src/android/view/cts/WindowTest.java
index dcfcfb7..bc786af 100644
--- a/tests/tests/view/src/android/view/cts/WindowTest.java
+++ b/tests/tests/view/src/android/view/cts/WindowTest.java
@@ -16,7 +16,8 @@
 
 package android.view.cts;
 
-import com.android.cts.view.R;
+import android.view.ContextThemeWrapper;
+import android.view.cts.R;
 
 import android.app.Instrumentation;
 import android.app.Presentation;
@@ -80,7 +81,7 @@
     private VirtualDisplay mVirtualDisplay;
 
     public WindowTest() {
-        super("com.android.cts.view", WindowCtsActivity.class);
+        super("android.view.cts", WindowCtsActivity.class);
     }
 
     @Override
@@ -292,7 +293,7 @@
         int screenHeight = dm.heightPixels;
         assertTrue(decor.getWidth() >= screenWidth);
         assertTrue(decor.getHeight() >= screenHeight);
-        assertSame(mWindow.getContext(), decor.getContext());
+        assertTrue(decor.getContext() instanceof ContextThemeWrapper);
     }
 
     /**
@@ -868,6 +869,9 @@
         public void addContentView(View view, ViewGroup.LayoutParams params) {
         }
 
+        public void clearContentView() {
+        }
+
         public View getCurrentFocus() {
             return null;
         }
@@ -1025,9 +1029,23 @@
         }
 
         @Override
+        public void setDecorCaptionShade(int decorCaptionShade) {
+
+        }
+
+        @Override
+        public void setResizingCaptionDrawable(Drawable drawable) {
+
+        }
+
+        @Override
         public int getNavigationBarColor() {
             return 0;
         }
+
+        @Override
+        public void onMultiWindowModeChanged() {
+        }
     }
 
     private class MockWindowCallback implements Window.Callback {
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java b/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java
index 30edecb..69659a2 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java
@@ -16,7 +16,7 @@
 
 package android.view.inputmethod.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 
 import android.app.Instrumentation;
@@ -48,7 +48,7 @@
     private Instrumentation mInstrumentation;
 
     public BaseInputConnectionTest() {
-        super("com.android.cts.view", InputMethodCtsActivity.class);
+        super("android.view.cts", InputMethodCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java b/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java
index 1981d6f..9184881 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java
@@ -21,6 +21,7 @@
 import android.os.Parcel;
 import android.test.AndroidTestCase;
 import android.text.TextUtils;
+import android.util.LocaleList;
 import android.util.Printer;
 import android.view.inputmethod.EditorInfo;
 
@@ -41,13 +42,14 @@
         info.initialSelStart = 0;
         info.inputType = EditorInfo.TYPE_MASK_CLASS;
         info.label = "label";
-        info.packageName = "com.android.cts.view";
+        info.packageName = "android.view.cts";
         info.privateImeOptions = "privateIme";
         Bundle b = new Bundle();
         String key = "bundleKey";
         String value = "bundleValue";
         b.putString(key, value);
         info.extras = b;
+        info.locales = LocaleList.forLanguageTags("en-PH,en-US");
 
         assertEquals(0, info.describeContents());
 
@@ -70,6 +72,7 @@
         assertEquals(info.actionLabel.toString(), targetInfo.actionLabel.toString());
         assertEquals(info.label.toString(), targetInfo.label.toString());
         assertEquals(info.extras.getString(key), targetInfo.extras.getString(key));
+        assertEquals(info.locales, targetInfo.locales);
 
         TestPrinter printer = new TestPrinter();
         String prefix = "TestEditorInfo";
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/InputMethodCtsActivity.java b/tests/tests/view/src/android/view/inputmethod/cts/InputMethodCtsActivity.java
index 45e5ff2..acbe8a1 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/InputMethodCtsActivity.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/InputMethodCtsActivity.java
@@ -17,7 +17,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 public class InputMethodCtsActivity extends Activity {
     @Override
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/InputMethodManagerTest.java b/tests/tests/view/src/android/view/inputmethod/cts/InputMethodManagerTest.java
index b84292f..d03bab5 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/InputMethodManagerTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/InputMethodManagerTest.java
@@ -15,7 +15,7 @@
  */
 package android.view.inputmethod.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.app.Instrumentation;
 import android.content.Context;
@@ -38,7 +38,7 @@
                   extends ActivityInstrumentationTestCase2<InputMethodCtsActivity> {
 
     public InputMethodManagerTest() {
-        super("com.android.cts.view", InputMethodCtsActivity.class);
+        super("android.view.cts", InputMethodCtsActivity.class);
     }
 
     private InputMethodCtsActivity mActivity;
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/KeyboardTest.java b/tests/tests/view/src/android/view/inputmethod/cts/KeyboardTest.java
index ce7f9d7..f56ad0e 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/KeyboardTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/KeyboardTest.java
@@ -16,7 +16,7 @@
 
 package android.view.inputmethod.cts;
 
-import com.android.cts.view.R;
+import android.view.cts.R;
 
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
diff --git a/tests/tests/voiceinteraction/Android.mk b/tests/tests/voiceinteraction/Android.mk
index b8f95e3..2d0666f 100644
--- a/tests/tests/voiceinteraction/Android.mk
+++ b/tests/tests/voiceinteraction/Android.mk
@@ -27,6 +27,11 @@
 
 LOCAL_PACKAGE_NAME := CtsVoiceInteractionTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/voiceinteraction/AndroidTest.xml b/tests/tests/voiceinteraction/AndroidTest.xml
index fa1ab70..2aba101 100644
--- a/tests/tests/voiceinteraction/AndroidTest.xml
+++ b/tests/tests/voiceinteraction/AndroidTest.xml
@@ -13,11 +13,14 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Test module config for VoiceInteraction">
-    <include name="common-config" />
-    <option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionService.apk" />
-    <option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionApp.apk" />
-    <option name="run-command:run-command"
-         value="settings put secure voice_interaction_service android.voiceinteraction.service/.MainInteractionService" />
-    <option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionTestCases.apk" />
+<configuration description="Config for CTS Voice Interaction test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsVoiceInteractionService.apk" />
+        <option name="test-file-name" value="CtsVoiceInteractionApp.apk" />
+        <option name="test-file-name" value="CtsVoiceInteractionTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.voiceinteraction.cts" />
+    </test>
 </configuration>
diff --git a/tests/tests/voiceinteraction/OldAndroidTest.xml b/tests/tests/voiceinteraction/OldAndroidTest.xml
new file mode 100644
index 0000000..fa1ab70
--- /dev/null
+++ b/tests/tests/voiceinteraction/OldAndroidTest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Test module config for VoiceInteraction">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionService.apk" />
+    <option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionApp.apk" />
+    <option name="run-command:run-command"
+         value="settings put secure voice_interaction_service android.voiceinteraction.service/.MainInteractionService" />
+    <option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionTestCases.apk" />
+</configuration>
diff --git a/tests/tests/voiceinteraction/service/Android.mk b/tests/tests/voiceinteraction/service/Android.mk
index 4338f13..705ef5b 100644
--- a/tests/tests/voiceinteraction/service/Android.mk
+++ b/tests/tests/voiceinteraction/service/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_PACKAGE_NAME := CtsVoiceInteractionService
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/voiceinteraction/testapp/Android.mk b/tests/tests/voiceinteraction/testapp/Android.mk
index 7453880..ae42d34 100644
--- a/tests/tests/voiceinteraction/testapp/Android.mk
+++ b/tests/tests/voiceinteraction/testapp/Android.mk
@@ -29,4 +29,7 @@
 
 LOCAL_SDK_VERSION := current
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/voicesettings/Android.mk b/tests/tests/voicesettings/Android.mk
index 71fead6..91d013d 100644
--- a/tests/tests/voicesettings/Android.mk
+++ b/tests/tests/voicesettings/Android.mk
@@ -27,6 +27,11 @@
 
 LOCAL_PACKAGE_NAME := CtsVoiceSettingsTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/voicesettings/AndroidTest.xml b/tests/tests/voicesettings/AndroidTest.xml
index e3be691..64f5335 100644
--- a/tests/tests/voicesettings/AndroidTest.xml
+++ b/tests/tests/voicesettings/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,10 +13,16 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Test module config for VoiceInteraction">
-    <include name="common-config" />
-    <option name="cts-apk-installer:test-file-name" value="CtsVoiceSettingsService.apk" />
-    <option name="run-command:run-command"
-         value="settings put secure voice_interaction_service android.voicesettings.service/.MainInteractionService" />
-    <option name="cts-apk-installer:test-file-name" value="CtsVoiceSettingsTestCases.apk" />
+<configuration description="Config for CTS Voice Settings test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsVoiceSettingsService.apk" />
+        <option name="test-file-name" value="CtsVoiceSettingsTestCases.apk" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="settings put secure voice_interaction_service android.voicesettings.service/.MainInteractionService" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.voicesettings.cts" />
+    </test>
 </configuration>
diff --git a/tests/tests/voicesettings/OldAndroidTest.xml b/tests/tests/voicesettings/OldAndroidTest.xml
new file mode 100644
index 0000000..246bf06
--- /dev/null
+++ b/tests/tests/voicesettings/OldAndroidTest.xml
@@ -0,0 +1,20 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Test module config for VoiceSettings">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsVoiceSettingsService.apk" />
+    <option name="run-command:run-command"
+         value="settings put secure voice_interaction_service android.voicesettings.service/.MainInteractionService" />
+</configuration>
diff --git a/tests/tests/voicesettings/service/Android.mk b/tests/tests/voicesettings/service/Android.mk
index 97866d5..f23a136 100644
--- a/tests/tests/voicesettings/service/Android.mk
+++ b/tests/tests/voicesettings/service/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_PACKAGE_NAME := CtsVoiceSettingsService
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/webkit/Android.mk b/tests/tests/webkit/Android.mk
index 17a1f27..85377ae 100644
--- a/tests/tests/webkit/Android.mk
+++ b/tests/tests/webkit/Android.mk
@@ -29,6 +29,9 @@
 
 LOCAL_PACKAGE_NAME := CtsWebkitTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/webkit/AndroidManifest.xml b/tests/tests/webkit/AndroidManifest.xml
index fa25824..44df7c4 100644
--- a/tests/tests/webkit/AndroidManifest.xml
+++ b/tests/tests/webkit/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.webkit">
+    package="android.webkit.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
@@ -59,7 +59,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.webkit"
+                     android:targetPackage="android.webkit.cts"
                      android:label="CTS tests of android.webkit">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/webkit/AndroidTest.xml b/tests/tests/webkit/AndroidTest.xml
new file mode 100644
index 0000000..e6649e1
--- /dev/null
+++ b/tests/tests/webkit/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Webkit test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.WifiCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsWebkitTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.webkit.cts" />
+        <option name="runtime-hint" value="6m39s" />
+    </test>
+
+</configuration>
diff --git a/tests/tests/webkit/assets/webkit/test_loginForm.html b/tests/tests/webkit/assets/webkit/test_loginForm.html
new file mode 100644
index 0000000..0935cf1
--- /dev/null
+++ b/tests/tests/webkit/assets/webkit/test_loginForm.html
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2009 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.
+-->
+
+<html>
+    <body>
+        <form>
+            <input type='text' name='username' value='Cts Test'/>
+            <input type='submit' name='submit' value='Submit'/>
+        </form>
+    </body>
+</html>
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
index 856b4aa..ffde739 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
@@ -42,7 +42,7 @@
     private WebViewOnUiThread mOnUiThread;
 
     public CookieManagerTest() {
-        super("com.android.cts.webkit", CookieSyncManagerCtsActivity.class);
+        super("android.webkit.cts", CookieSyncManagerCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
index 555266b..cca7e35 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
@@ -30,7 +30,7 @@
     private static final long WAIT_TIME = 50;
 
     public CookieTest() {
-        super("com.android.cts.webkit", CookieSyncManagerCtsActivity.class);
+        super("android.webkit.cts", CookieSyncManagerCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java b/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
index 32b6167..83330d4 100644
--- a/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
@@ -110,7 +110,7 @@
     private List<String> mProviders;
 
     public GeolocationTest() throws Exception {
-        super("com.android.cts.webkit", WebViewCtsActivity.class);
+        super("android.webkit.cts", WebViewCtsActivity.class);
     }
 
     // Both this test and WebViewOnUiThread need to override some of the methods on WebViewClient,
diff --git a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
index 5c86987..10bf6d8 100644
--- a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
@@ -38,7 +38,7 @@
     private WebViewOnUiThread mOnUiThread;
 
     public HttpAuthHandlerTest() {
-        super("com.android.cts.webkit", WebViewCtsActivity.class);
+        super("android.webkit.cts", WebViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
index 2a6af6e..6ffe69c 100644
--- a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
@@ -38,7 +38,7 @@
     private static final String BASE_URI = "http://www.example.com";
 
     public PostMessageTest() {
-        super("com.android.cts.webkit", WebViewCtsActivity.class);
+        super("android.webkit.cts", WebViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
index 1ab5e5a..68d944b 100644
--- a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
+++ b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
@@ -55,6 +55,8 @@
     public static final String BLANK_PAGE_URL = "webkit/test_blankPage.html";
     public static final String ADD_JAVA_SCRIPT_INTERFACE_URL = "webkit/test_jsInterface.html";
 
+    public static final String LOGIN_FORM_URL = "webkit/test_loginForm.html";
+
     public static final String EXT_WEB_URL1 = "http://www.example.com/";
 
     public static final String LOCAL_FILESYSTEM_URL = "file:///etc/hosts";
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java b/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
index 7d25b84..e7d6211 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
@@ -31,7 +31,7 @@
     private WebViewOnUiThread mOnUiThread;
 
     public WebBackForwardListTest() {
-        super("com.android.cts.webkit", WebViewCtsActivity.class);
+        super("android.webkit.cts", WebViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
index a6b647df..dc9e615 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
@@ -48,7 +48,7 @@
     };
 
     public WebHistoryItemTest() {
-        super("com.android.cts.webkit", WebViewCtsActivity.class);
+        super("android.webkit.cts", WebViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 592e308..7729baf 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -64,7 +64,7 @@
     private Context mContext;
 
     public WebSettingsTest() {
-        super("com.android.cts.webkit", WebViewCtsActivity.class);
+        super("android.webkit.cts", WebViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 0697429..1267ccb 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -34,11 +34,14 @@
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
+import android.util.Pair;
 
 import java.io.ByteArrayInputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
 
 public class WebViewClientTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     private static final long TEST_TIMEOUT = 5000;
@@ -48,7 +51,7 @@
     private CtsTestServer mWebServer;
 
     public WebViewClientTest() {
-        super("com.android.cts.webkit", WebViewCtsActivity.class);
+        super("android.webkit.cts", WebViewCtsActivity.class);
     }
 
     @Override
@@ -85,7 +88,7 @@
             return;
         }
         final WebViewClient webViewClient = new WebViewClient();
-        assertFalse(webViewClient.shouldOverrideUrlLoading(mOnUiThread.getWebView(), null));
+        assertFalse(webViewClient.shouldOverrideUrlLoading(mOnUiThread.getWebView(), new String()));
     }
 
     // Verify shouldoverrideurlloading called on top level navigation
@@ -210,6 +213,40 @@
         }.run();
     }
 
+    public void testOnReceivedLoginRequest() throws Exception {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        mOnUiThread.setWebViewClient(webViewClient);
+        TestWebServer testServer = null;
+        //set the url and html
+        final String path = "/main";
+        final String page = "<head></head><body>test onReceivedLoginRequest</body>";
+        final String headerName = "x-auto-login";
+        final String headerValue = "realm=com.google&account=foo%40bar.com&args=random_string";
+        List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>();
+        headers.add(Pair.create(headerName, headerValue));
+
+        try {
+            testServer = new TestWebServer(false);
+            String url = testServer.setResponse(path, page, headers);
+            assertFalse(webViewClient.hasOnReceivedLoginRequest());
+            mOnUiThread.loadUrlAndWaitForCompletion(url);
+            assertTrue(webViewClient.hasOnReceivedLoginRequest());
+            new PollingCheck(TEST_TIMEOUT) {
+                @Override
+                protected boolean check() {
+                    return webViewClient.hasOnReceivedLoginRequest();
+                }
+            }.run();
+           assertEquals("com.google", webViewClient.getLoginRequestRealm());
+           assertEquals("foo@bar.com", webViewClient.getLoginRequestAccount());
+           assertEquals("random_string", webViewClient.getLoginRequestArgs());
+        } finally {
+            testServer.shutdown();
+        }
+    }
     public void testOnReceivedError() throws Exception {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
@@ -541,6 +578,10 @@
         private boolean mOnFormResubmissionCalled;
         private boolean mDoUpdateVisitedHistoryCalled;
         private boolean mOnReceivedHttpAuthRequestCalled;
+        private boolean mOnReceivedLoginRequest;
+        private String mOnReceivedLoginAccount;
+        private String mOnReceivedLoginArgs;
+        private String mOnReceivedLoginRealm;
         private boolean mOnUnhandledKeyEventCalled;
         private boolean mOnScaleChangedCalled;
         private int mShouldOverrideUrlLoadingCallCount;
@@ -566,6 +607,10 @@
             return mOnReceivedErrorCode;
         }
 
+        public boolean hasOnReceivedLoginRequest() {
+            return mOnReceivedLoginRequest;
+        }
+
         public WebResourceError hasOnReceivedResourceError() {
             return mOnReceivedResourceError;
         }
@@ -602,6 +647,18 @@
             return mLastShouldOverrideUrl;
         }
 
+        public String getLoginRequestRealm() {
+            return mOnReceivedLoginRealm;
+        }
+
+        public String getLoginRequestAccount() {
+            return mOnReceivedLoginAccount;
+        }
+
+        public String getLoginRequestArgs() {
+            return mOnReceivedLoginArgs;
+        }
+
         @Override
         public void onPageStarted(WebView view, String url, Bitmap favicon) {
             super.onPageStarted(view, url, favicon);
@@ -645,6 +702,16 @@
         }
 
         @Override
+        public void onReceivedLoginRequest(WebView view, String realm, String account,
+                String args) {
+            super.onReceivedLoginRequest(view, realm, account, args);
+            mOnReceivedLoginRequest = true;
+            mOnReceivedLoginRealm = realm;
+            mOnReceivedLoginAccount = account;
+            mOnReceivedLoginArgs = args;
+       }
+
+        @Override
         public void onFormResubmission(WebView view, Message dontResend, Message resend) {
             mOnFormResubmissionCalled = true;
             dontResend.sendToTarget();
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewCtsActivity.java b/tests/tests/webkit/src/android/webkit/cts/WebViewCtsActivity.java
index 9af7266..1b05154 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewCtsActivity.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.webkit.cts;
 
-import com.android.cts.webkit.R;
+import android.webkit.cts.R;
 
 import android.app.Activity;
 import android.cts.util.NullWebViewUtils;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java
index 6555731..e07267f 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java
@@ -430,7 +430,7 @@
     private WebViewOnUiThread mOnUiThread;
 
     public WebViewSslTest() {
-        super("com.android.cts.webkit", WebViewCtsActivity.class);
+        super("android.webkit.cts", WebViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
index 776cfab..6768b6f 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
@@ -39,7 +39,7 @@
     private WebViewStartupCtsActivity mActivity;
 
     public WebViewStartupTest() {
-        super("com.android.cts.webkit", WebViewStartupCtsActivity.class);
+        super("android.webkit.cts", WebViewStartupCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 4c5b2db..a79e5ba 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -1126,6 +1126,39 @@
         }.run();
     }
 
+    public void testClearFormData() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        try {
+            startWebServer(false);
+            WebSettings settings = mOnUiThread.getSettings();
+            settings.setDatabaseEnabled(true);
+            WebViewDatabase webViewDatabase = WebViewDatabase.getInstance(getActivity());
+            webViewDatabase.clearFormData();
+            final String url = mWebServer.getAssetUrl(TestHtmlConstants.LOGIN_FORM_URL);
+            mOnUiThread.loadUrlAndWaitForCompletion(url);
+            new PollingCheck(TEST_TIMEOUT) {
+                @Override
+                public boolean check() {
+                    return !WebViewDatabase.getInstance(getActivity()).hasFormData();
+                }
+            }.run();
+
+            // click submit
+            moveFocusDown();
+            getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
+            new PollingCheck(TEST_TIMEOUT) {
+                @Override
+                public boolean check() {
+                    return WebViewDatabase.getInstance(getActivity()).hasFormData();
+                }
+            }.run();
+        } finally {
+            WebViewDatabase.getInstance(getActivity()).clearFormData();
+        }
+    }
+
     @UiThreadTest
     public void testAccessHttpAuthUsernamePassword() {
         if (!NullWebViewUtils.isWebViewAvailable()) {
@@ -1592,7 +1625,7 @@
         } while (mOnUiThread.pageDown(false));
 
         waitForFlingDone(mOnUiThread);
-        int bottomScrollY = mOnUiThread.getScrollY();
+        final int bottomScrollY = mOnUiThread.getScrollY();
 
         assertTrue(mOnUiThread.pageUp(false));
 
@@ -1601,17 +1634,25 @@
         } while (mOnUiThread.pageUp(false));
 
         waitForFlingDone(mOnUiThread);
-        int topScrollY = mOnUiThread.getScrollY();
+        final int topScrollY = mOnUiThread.getScrollY();
 
         // jump to the bottom
         assertTrue(mOnUiThread.pageDown(true));
-        waitForFlingDone(mOnUiThread);
-        assertEquals(bottomScrollY, mOnUiThread.getScrollY());
+        new PollingCheck() {
+            @Override
+            protected boolean check() {
+                return bottomScrollY == mOnUiThread.getScrollY();
+            }
+        }.run();
 
         // jump to the top
         assertTrue(mOnUiThread.pageUp(true));
-        waitForFlingDone(mOnUiThread);
-        assertEquals(topScrollY, mOnUiThread.getScrollY());
+         new PollingCheck() {
+            @Override
+            protected boolean check() {
+                return topScrollY == mOnUiThread.getScrollY();
+            }
+        }.run();
     }
 
     public void testGetContentHeight() throws Throwable {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java b/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
index 1db7fca..4fa9b4f 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
@@ -27,7 +27,7 @@
         extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
 
     public WebView_WebViewTransportTest() {
-        super("com.android.cts.webkit", WebViewCtsActivity.class);
+        super("android.webkit.cts", WebViewCtsActivity.class);
     }
 
     @UiThreadTest
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
index 505f82c..fa2b60a 100644
--- a/tests/tests/widget/Android.mk
+++ b/tests/tests/widget/Android.mk
@@ -21,7 +21,7 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES += android-common ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES += mockito-target android-common ctsdeviceutil ctstestrunner
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
@@ -29,4 +29,7 @@
 
 LOCAL_PACKAGE_NAME := CtsWidgetTestCases
 
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index bc43106..576e751 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.widget">
+    package="android.widget.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application android:label="Android TestCase"
@@ -355,7 +355,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.widget"
+                     android:targetPackage="android.widget.cts"
                      android:label="CTS tests of android.widget">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/widget/AndroidTest.xml b/tests/tests/widget/AndroidTest.xml
new file mode 100644
index 0000000..d943b85
--- /dev/null
+++ b/tests/tests/widget/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Widget test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.WifiCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsWidgetTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.widget.cts" />
+        <option name="runtime-hint" value="3m" />
+    </test>
+</configuration>
diff --git a/tests/tests/widget/res/layout/digitalclock_layout.xml b/tests/tests/widget/res/layout/digitalclock_layout.xml
index d405af2..618dbea 100644
--- a/tests/tests/widget/res/layout/digitalclock_layout.xml
+++ b/tests/tests/widget/res/layout/digitalclock_layout.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<com.android.cts.widget.alarmclock.DigitalClock android:id="@+id/digitalClock"
+<android.widget.cts.alarmclock.DigitalClock android:id="@+id/digitalClock"
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="wrap_content"
      android:layout_height="208dip"
@@ -45,4 +45,4 @@
              android:text="@string/pm"
              android:textSize="28sp"/>
      </LinearLayout>
-</com.android.cts.widget.alarmclock.DigitalClock>
+</android.widget.cts.alarmclock.DigitalClock>
diff --git a/tests/tests/widget/res/layout/linearlayout_layout.xml b/tests/tests/widget/res/layout/linearlayout_layout.xml
index c70937d..8881552 100644
--- a/tests/tests/widget/res/layout/linearlayout_layout.xml
+++ b/tests/tests/widget/res/layout/linearlayout_layout.xml
@@ -15,6 +15,7 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:id="@+id/linearlayout_root"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="vertical">
diff --git a/tests/tests/widget/res/layout/toolbar_layout.xml b/tests/tests/widget/res/layout/toolbar_layout.xml
new file mode 100644
index 0000000..42e661b
--- /dev/null
+++ b/tests/tests/widget/res/layout/toolbar_layout.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
+         android:layout_width="match_parent"
+         android:layout_height="wrap_content"
+         android:id="@+id/toolbar"
+         android:titleMargin="5px"
+         android:titleMarginTop="10px"
+         android:titleMarginEnd="15px"
+         android:titleMarginBottom="20px" />
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
index 2b38827..89a3448 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -73,7 +73,7 @@
     private static final float DELTA = 0.001f;
 
     public AbsListViewTest() {
-        super("com.android.cts.widget", ListViewCtsActivity.class);
+        super("android.widget.cts", ListViewCtsActivity.class);
     }
 
 
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListView_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/AbsListView_LayoutParamsTest.java
index 305a9e2..7e88a19 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListView_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListView_LayoutParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/tests/tests/widget/src/android/widget/cts/AbsSeekBarTest.java b/tests/tests/widget/src/android/widget/cts/AbsSeekBarTest.java
index dfad3bbb..9342d72 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsSeekBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsSeekBarTest.java
@@ -21,7 +21,7 @@
 import android.graphics.PorterDuff;
 import android.test.UiThreadTest;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.app.Activity;
@@ -42,7 +42,7 @@
  */
 public class AbsSeekBarTest extends ActivityInstrumentationTestCase2<ProgressBarCtsActivity> {
     public AbsSeekBarTest() {
-        super("com.android.cts.widget", ProgressBarCtsActivity.class);
+        super("android.widget.cts", ProgressBarCtsActivity.class);
     }
 
     private Activity mActivity;
diff --git a/tests/tests/widget/src/android/widget/cts/AbsSpinnerTest.java b/tests/tests/widget/src/android/widget/cts/AbsSpinnerTest.java
index 9669c7c..e07e8b1 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsSpinnerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsSpinnerTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -43,7 +43,7 @@
     private Context mContext;
 
     public AbsSpinnerTest() {
-        super("com.android.cts.widget", RelativeLayoutCtsActivity.class);
+        super("android.widget.cts", RelativeLayoutCtsActivity.class);
     }
 
     @Override
@@ -78,7 +78,7 @@
     public void testSetSelectionIntBoolean() {
         AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
         ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
-                com.android.cts.widget.R.array.string, android.R.layout.simple_spinner_item);
+                android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
         absSpinner.setAdapter(adapter);
         assertEquals(0, absSpinner.getSelectedItemPosition());
@@ -101,7 +101,7 @@
     public void testSetSelectionInt() {
         AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
         ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
-                com.android.cts.widget.R.array.string, android.R.layout.simple_spinner_item);
+                android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
         absSpinner.setAdapter(adapter);
         assertEquals(0, absSpinner.getSelectedItemPosition());
@@ -123,7 +123,7 @@
     public void testAccessAdapter() {
         AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
         ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
-                com.android.cts.widget.R.array.string, android.R.layout.simple_spinner_item);
+                android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
 
         absSpinner.setAdapter(adapter);
@@ -159,7 +159,7 @@
         AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
 
         ArrayAdapter<CharSequence> adapter1 = ArrayAdapter.createFromResource(mContext,
-                com.android.cts.widget.R.array.string, android.R.layout.simple_spinner_item);
+                android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
 
         absSpinner.setAdapter(adapter1);
         assertEquals(adapter1.getCount(), absSpinner.getCount());
@@ -236,7 +236,7 @@
     public void testOnSaveAndRestoreInstanceState() {
         AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
         ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
-                com.android.cts.widget.R.array.string, android.R.layout.simple_spinner_item);
+                android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
         absSpinner.setAdapter(adapter);
         assertEquals(0, absSpinner.getSelectedItemPosition());
diff --git a/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java b/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java
index bac2479..a838f65 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -46,7 +46,7 @@
     private LayoutParams mAbsoluteLayoutParams;
 
     public AbsoluteLayoutTest() {
-        super("com.android.cts.widget", CtsActivity.class);
+        super("android.widget.cts", CtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/AbsoluteLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/AbsoluteLayout_LayoutParamsTest.java
index ebc4e74..2723581 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsoluteLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsoluteLayout_LayoutParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/tests/tests/widget/src/android/widget/cts/AdapterViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/AdapterViewCtsActivity.java
index 956ff9a..a85e365 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterViewCtsActivity.java
@@ -25,7 +25,7 @@
 import android.widget.ArrayAdapter;
 import android.widget.ListView;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * A minimal application for AdapterView test.
diff --git a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
index ccbdd56..1b9137f 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
@@ -39,7 +39,7 @@
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.provider.Settings;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 public class AdapterViewTest extends ActivityInstrumentationTestCase2<AdapterViewCtsActivity> {
@@ -55,7 +55,7 @@
     private AdapterView<ListAdapter> mAdapterView;
 
     public AdapterViewTest() {
-        super("com.android.cts.widget", AdapterViewCtsActivity.class);
+        super("android.widget.cts", AdapterViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/AdapterView_AdapterContextMenuInfoTest.java b/tests/tests/widget/src/android/widget/cts/AdapterView_AdapterContextMenuInfoTest.java
index fde6095..17c7a1e 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterView_AdapterContextMenuInfoTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterView_AdapterContextMenuInfoTest.java
@@ -16,7 +16,6 @@
 
 package android.widget.cts;
 
-
 import android.test.AndroidTestCase;
 import android.view.View;
 import android.widget.AdapterView;
diff --git a/tests/tests/widget/src/android/widget/cts/AnalogClockTest.java b/tests/tests/widget/src/android/widget/cts/AnalogClockTest.java
index ef1a45d..fae6516 100644
--- a/tests/tests/widget/src/android/widget/cts/AnalogClockTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AnalogClockTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -33,7 +33,7 @@
     private Activity mActivity;
 
     public AnalogClockTest() {
-        super("com.android.cts.widget", FrameLayoutCtsActivity.class);
+        super("android.widget.cts", FrameLayoutCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
index fdca64c..03677f2 100644
--- a/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
@@ -29,7 +29,7 @@
 import android.widget.Filter;
 import android.widget.TextView;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 public class ArrayAdapterTest extends InstrumentationTestCase {
diff --git a/tests/tests/widget/src/android/widget/cts/AutoCompleteCtsActivity.java b/tests/tests/widget/src/android/widget/cts/AutoCompleteCtsActivity.java
index 3d68f3e..1a12d66 100644
--- a/tests/tests/widget/src/android/widget/cts/AutoCompleteCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/AutoCompleteCtsActivity.java
@@ -19,7 +19,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * A minimal application for AutoCompleteTextView test.
diff --git a/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
index c08abbc..eb22d6b 100644
--- a/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -53,7 +53,7 @@
      * Instantiates a new text view test.
      */
     public AutoCompleteTextViewTest() {
-        super("com.android.cts.widget", AutoCompleteCtsActivity.class);
+        super("android.widget.cts", AutoCompleteCtsActivity.class);
     }
 
     /** The m activity. */
diff --git a/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java b/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java
index 0369259..7659c1e 100644
--- a/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java
@@ -16,7 +16,6 @@
 
 package android.widget.cts;
 
-
 import android.database.DataSetObserver;
 import android.test.AndroidTestCase;
 import android.view.View;
diff --git a/tests/tests/widget/src/android/widget/cts/ButtonTest.java b/tests/tests/widget/src/android/widget/cts/ButtonTest.java
index 47d7108..9da2ecf 100644
--- a/tests/tests/widget/src/android/widget/cts/ButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ButtonTest.java
@@ -24,7 +24,7 @@
 import android.util.Xml;
 import android.widget.Button;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 public class ButtonTest extends AndroidTestCase {
diff --git a/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java b/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
index 21e463f..b3a6e67 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java
index a0ed498..52bef54 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java b/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
index c5d3bd1..039ca70 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
@@ -16,7 +16,8 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.os.Parcelable;
+import android.widget.cts.R;
 
 
 import android.app.Activity;
@@ -44,7 +45,7 @@
     private Instrumentation mInstrumentation;
 
     public CheckedTextViewTest() {
-        super("com.android.cts.widget", CheckedTextViewCtsActivity.class);
+        super("android.widget.cts", CheckedTextViewCtsActivity.class);
     }
 
     @Override
@@ -266,6 +267,35 @@
         assertFalse(checkedTextView.isLayoutRequested());
     }
 
+    public void testSetCheckMarkByMixedTypes() {
+        CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
+        cleanUpForceLayoutFlags(checkedTextView);
+
+        // Specifically test for b/22626247 (AOSP issue 180455).
+        checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
+        checkedTextView.setCheckMarkDrawable(null);
+        checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
+        assertNotNull(checkedTextView.getCheckMarkDrawable());
+    }
+
+    public void testAccessInstanceState() {
+        CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
+        Parcelable state;
+
+        assertFalse(checkedTextView.isChecked());
+        assertFalse(checkedTextView.getFreezesText());
+
+        state = checkedTextView.onSaveInstanceState();
+        assertNotNull(state);
+        assertFalse(checkedTextView.getFreezesText());
+
+        checkedTextView.setChecked(true);
+
+        checkedTextView.onRestoreInstanceState(state);
+        assertFalse(checkedTextView.isChecked());
+        assertTrue(checkedTextView.isLayoutRequested());
+    }
+
     public void testOnDraw() {
         // Do not test. Implementation details.
     }
diff --git a/tests/tests/widget/src/android/widget/cts/ChronometerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ChronometerCtsActivity.java
index 3a7833d..7925b49 100644
--- a/tests/tests/widget/src/android/widget/cts/ChronometerCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ChronometerCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.ViewGroup;
diff --git a/tests/tests/widget/src/android/widget/cts/ChronometerTest.java b/tests/tests/widget/src/android/widget/cts/ChronometerTest.java
index 7910274..ff1435f 100644
--- a/tests/tests/widget/src/android/widget/cts/ChronometerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ChronometerTest.java
@@ -28,7 +28,7 @@
 public class ChronometerTest extends ActivityInstrumentationTestCase2<ChronometerCtsActivity> {
     private ChronometerCtsActivity mActivity;
     public ChronometerTest() {
-        super("com.android.cts.widget", ChronometerCtsActivity.class);
+        super("android.widget.cts", ChronometerCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java b/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
index 98bf047..4b32eff 100644
--- a/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
@@ -22,7 +22,7 @@
 import android.graphics.PorterDuff;
 import android.view.LayoutInflater;
 import android.widget.ToggleButton;
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
index 730083e..b590199 100644
--- a/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
@@ -37,7 +37,7 @@
 import android.widget.FilterQueryProvider;
 import android.widget.TextView;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * Test {@link CursorAdapter}.
diff --git a/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
index f74b9972..5295730 100644
--- a/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
@@ -32,7 +32,7 @@
 import android.widget.FilterQueryProvider;
 import android.widget.TextView;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 /**
diff --git a/tests/tests/widget/src/android/widget/cts/DatePickerTest.java b/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
index 3fa238e..c48f684 100644
--- a/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.content.Context;
 import android.content.res.XmlResourceParser;
diff --git a/tests/tests/widget/src/android/widget/cts/DialerFilterCtsActivity.java b/tests/tests/widget/src/android/widget/cts/DialerFilterCtsActivity.java
index 572d3fb..406a49a 100644
--- a/tests/tests/widget/src/android/widget/cts/DialerFilterCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/DialerFilterCtsActivity.java
@@ -18,7 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * A minimal application for DialerFilter test.
diff --git a/tests/tests/widget/src/android/widget/cts/DialerFilterTest.java b/tests/tests/widget/src/android/widget/cts/DialerFilterTest.java
index 68a17e7..a99f56a 100644
--- a/tests/tests/widget/src/android/widget/cts/DialerFilterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DialerFilterTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -45,7 +45,7 @@
     private DialerFilter mDialerFilter;
 
     public DialerFilterTest() {
-        super("com.android.cts.widget", DialerFilterCtsActivity.class);
+        super("android.widget.cts", DialerFilterCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/DigitalClockCtsActivity.java b/tests/tests/widget/src/android/widget/cts/DigitalClockCtsActivity.java
index 68cb3f0..d92651e 100644
--- a/tests/tests/widget/src/android/widget/cts/DigitalClockCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/DigitalClockCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/DigitalClockTest.java b/tests/tests/widget/src/android/widget/cts/DigitalClockTest.java
index 86a9672..2bfcc59 100644
--- a/tests/tests/widget/src/android/widget/cts/DigitalClockTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DigitalClockTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -42,7 +42,7 @@
     private Context mContext;
 
     public DigitalClockTest() {
-        super("com.android.cts.widget", DigitalClockCtsActivity.class);
+        super("android.widget.cts", DigitalClockCtsActivity.class);
     }
 
     @Override
@@ -114,7 +114,7 @@
     private AttributeSet getAttributeSet(int resourceId) {
         XmlResourceParser parser = mActivity.getResources().getXml(resourceId);
         try {
-            XmlUtils.beginDocument(parser, "com.android.cts.widget.alarmclock.DigitalClock");
+            XmlUtils.beginDocument(parser, "android.widget.cts.alarmclock.DigitalClock");
         } catch (XmlPullParserException e) {
             fail("unexpected XmlPullParserException.");
         } catch (IOException e) {
diff --git a/tests/tests/widget/src/android/widget/cts/EditTextTest.java b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
index 7a71a58..88fa2e0 100644
--- a/tests/tests/widget/src/android/widget/cts/EditTextTest.java
+++ b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
@@ -28,7 +28,7 @@
 import android.widget.EditText;
 import android.widget.TextView.BufferType;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 public class EditTextTest extends AndroidTestCase {
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java b/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
index ac48ed8..e773ebf 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/tests/tests/widget/src/android/widget/cts/FilterTest.java b/tests/tests/widget/src/android/widget/cts/FilterTest.java
index 2c598dd..7a1d111 100644
--- a/tests/tests/widget/src/android/widget/cts/FilterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FilterTest.java
@@ -32,7 +32,7 @@
     private MockFilter mMockFilter;
 
     public FilterTest() {
-        super("com.android.cts.widget", CtsActivity.class);
+        super("android.widget.cts", CtsActivity.class);
     }
 
     public void testConstructor() throws Throwable {
diff --git a/tests/tests/widget/src/android/widget/cts/FrameLayoutCtsActivity.java b/tests/tests/widget/src/android/widget/cts/FrameLayoutCtsActivity.java
index c638313..1f97af4 100644
--- a/tests/tests/widget/src/android/widget/cts/FrameLayoutCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/FrameLayoutCtsActivity.java
@@ -18,7 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * A minimal application for frame layout test.
diff --git a/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java b/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
index 31d9fff..1fc0cef 100644
--- a/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
@@ -23,7 +23,7 @@
 import android.graphics.ColorFilter;
 import android.graphics.PorterDuff;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -56,7 +56,7 @@
     private FrameLayout mFrameLayout;
 
     public FrameLayoutTest() {
-        super("com.android.cts.widget", FrameLayoutCtsActivity.class);
+        super("android.widget.cts", FrameLayoutCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
index 1e7082f..5774b53 100644
--- a/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
@@ -16,7 +16,8 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.view.Gravity;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -75,4 +76,47 @@
             // expected, test success.
         }
     }
+
+    public void testCopyConstructor() {
+        FrameLayout.LayoutParams copy;
+
+        final FrameLayout.LayoutParams fllp = new FrameLayout.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+        fllp.gravity = Gravity.BOTTOM;
+        fllp.leftMargin = 5;
+        fllp.topMargin = 10;
+        fllp.rightMargin = 15;
+        fllp.bottomMargin = 20;
+
+        copy = new FrameLayout.LayoutParams(fllp);
+        assertEquals("Width", fllp.width, copy.width);
+        assertEquals("Height", fllp.height, copy.height);
+        assertEquals("Gravity", fllp.gravity, copy.gravity);
+        assertEquals("Left margin", fllp.leftMargin, copy.leftMargin);
+        assertEquals("Top margin", fllp.topMargin, copy.topMargin);
+        assertEquals("Right margin", fllp.rightMargin, copy.rightMargin);
+        assertEquals("Bottom margin", fllp.bottomMargin, copy.bottomMargin);
+
+        final MarginLayoutParams mlp = new MarginLayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+        mlp.leftMargin = 5;
+        mlp.topMargin = 10;
+        mlp.rightMargin = 15;
+        mlp.bottomMargin = 20;
+
+        copy = new FrameLayout.LayoutParams(mlp);
+        assertEquals("Width", mlp.width, copy.width);
+        assertEquals("Height", mlp.height, copy.height);
+        assertEquals("Left margin", fllp.leftMargin, copy.leftMargin);
+        assertEquals("Top margin", fllp.topMargin, copy.topMargin);
+        assertEquals("Right margin", fllp.rightMargin, copy.rightMargin);
+        assertEquals("Bottom margin", fllp.bottomMargin, copy.bottomMargin);
+
+        final ViewGroup.LayoutParams vglp = new ViewGroup.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+        copy = new FrameLayout.LayoutParams(vglp);
+        assertEquals("Width", vglp.width, copy.width);
+        assertEquals("Height", vglp.height, copy.height);
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/GalleryCtsActivity.java b/tests/tests/widget/src/android/widget/cts/GalleryCtsActivity.java
index 8d32717..8039f47 100644
--- a/tests/tests/widget/src/android/widget/cts/GalleryCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/GalleryCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.content.Context;
diff --git a/tests/tests/widget/src/android/widget/cts/GalleryTest.java b/tests/tests/widget/src/android/widget/cts/GalleryTest.java
index 581107c..dd39461 100644
--- a/tests/tests/widget/src/android/widget/cts/GalleryTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GalleryTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -64,7 +64,7 @@
     private final static float DELTA = 0.01f;
 
     public GalleryTest() {
-        super("com.android.cts.widget", GalleryCtsActivity.class);
+        super("android.widget.cts", GalleryCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/Gallery_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/Gallery_LayoutParamsTest.java
index 0502e38..eacb676 100644
--- a/tests/tests/widget/src/android/widget/cts/Gallery_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/Gallery_LayoutParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/tests/tests/widget/src/android/widget/cts/GridLayoutCtsActivity.java b/tests/tests/widget/src/android/widget/cts/GridLayoutCtsActivity.java
index 3277ee8..bfbde22 100644
--- a/tests/tests/widget/src/android/widget/cts/GridLayoutCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/GridLayoutCtsActivity.java
@@ -18,7 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * A minimal application for {@link android.widget.GridLayout} test.
diff --git a/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java b/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java
index d701623..adbb285 100644
--- a/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java
@@ -27,7 +27,7 @@
 import android.widget.Button;
 import android.widget.GridLayout;
 import android.widget.TextView;
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 import org.xmlpull.v1.XmlPullParser;
 
 import static android.view.ViewGroup.LAYOUT_MODE_OPTICAL_BOUNDS;
@@ -117,7 +117,7 @@
     private Context mContext;
 
     public GridLayoutTest() {
-        super("com.android.cts.widget", GridLayoutCtsActivity.class);
+        super("android.widget.cts", GridLayoutCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/GridViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/GridViewCtsActivity.java
index 7a1182d..7b2e7a3 100644
--- a/tests/tests/widget/src/android/widget/cts/GridViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/GridViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/GridViewTest.java b/tests/tests/widget/src/android/widget/cts/GridViewTest.java
index 3c615bd..8698280 100644
--- a/tests/tests/widget/src/android/widget/cts/GridViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GridViewTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -57,7 +57,7 @@
     private Instrumentation mInstrumentation;
 
     public GridViewTest() {
-        super("com.android.cts.widget", GridViewCtsActivity.class);
+        super("android.widget.cts", GridViewCtsActivity.class);
     }
 
     private GridView findGridViewById(int id) {
diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java
index 312111a..a10e63a 100644
--- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
index 36398c3..1149d3b 100644
--- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -54,7 +54,7 @@
     private Activity mActivity;
 
     public HorizontalScrollViewTest() {
-        super("com.android.cts.widget", HorizontalScrollViewCtsActivity.class);
+        super("android.widget.cts", HorizontalScrollViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java b/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
index 374c9c2..05c0e3f 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java b/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
index 95f8d0c..a7bca5c 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ImageViewCtsActivity.java
index 295f3da..e68c986 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
index 8b50e2c..e0d821d 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
@@ -49,7 +49,7 @@
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 /**
@@ -60,7 +60,7 @@
     private Activity mActivity;
 
     public ImageViewTest() {
-        super("com.android.cts.widget", ImageViewCtsActivity.class);
+        super("android.widget.cts", ImageViewCtsActivity.class);
     }
 
     /**
diff --git a/tests/tests/widget/src/android/widget/cts/LayoutDirectionCtsActivity.java b/tests/tests/widget/src/android/widget/cts/LayoutDirectionCtsActivity.java
index 093f554..755091d 100644
--- a/tests/tests/widget/src/android/widget/cts/LayoutDirectionCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/LayoutDirectionCtsActivity.java
@@ -18,7 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * A minimal application for layout direction test.
diff --git a/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java b/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java
index c393e95..2369c5a 100644
--- a/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java
@@ -20,7 +20,7 @@
 import android.test.UiThreadTest;
 import android.view.ViewGroup;
 import android.widget.*;
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import static android.view.View.LAYOUT_DIRECTION_LTR;
 import static android.view.View.LAYOUT_DIRECTION_RTL;
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayoutCtsActivity.java b/tests/tests/widget/src/android/widget/cts/LinearLayoutCtsActivity.java
index 0cb5bc0..4a04b52 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayoutCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayoutCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
index 5815f9a..76fa782 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
@@ -16,6 +16,9 @@
 
 package android.widget.cts;
 
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewTreeObserver;
 import org.xmlpull.v1.XmlPullParser;
 
 import android.app.Activity;
@@ -31,7 +34,10 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test {@link LinearLayout}.
@@ -41,7 +47,7 @@
     private Activity mActivity;
 
     public LinearLayoutTest() {
-        super("com.android.cts.widget", LinearLayoutCtsActivity.class);
+        super("android.widget.cts", LinearLayoutCtsActivity.class);
     }
 
     @Override
@@ -327,6 +333,78 @@
         assertEquals(parent.getWidth(), rightView.getRight());
     }
 
+    private void checkBounds(final ViewGroup viewGroup, final View view,
+            final CountDownLatch countDownLatch, final int left, final int top,
+            final int width, final int height) {
+        viewGroup.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+            @Override
+            public boolean onPreDraw() {
+                assertEquals(left, view.getLeft());
+                assertEquals(top, view.getTop());
+                assertEquals(width, view.getWidth());
+                assertEquals(height, view.getHeight());
+                countDownLatch.countDown();
+                viewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
+                return true;
+            }
+        });
+    }
+
+    public void testVisibilityAffectsLayout() throws Throwable {
+        // Toggling view visibility between GONE/VISIBLE can affect the position of
+        // other children in that container. This test verifies that these changes
+        // on the first child of a LinearLayout affects the position of a second child
+        final int childWidth = 100;
+        final int childHeight = 200;
+        final LinearLayout parent = new LinearLayout(mActivity);
+        ViewGroup.LayoutParams parentParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+        parent.setLayoutParams(parentParams);
+        final View child1 = new View(mActivity);
+        child1.setBackgroundColor(Color.GREEN);
+        ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
+        child1.setLayoutParams(childParams);
+        final View child2 = new View(mActivity);
+        child2.setBackgroundColor(Color.RED);
+        childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
+        child2.setLayoutParams(childParams);
+        final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.linearlayout_root);
+
+        final CountDownLatch countDownLatch1 = new CountDownLatch(1);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                viewGroup.removeAllViews();
+                viewGroup.addView(parent);
+                parent.addView(child1);
+                parent.addView(child2);
+                checkBounds(viewGroup, child1, countDownLatch1, 0, 0, childWidth, childHeight);
+                checkBounds(viewGroup, child2, countDownLatch1,
+                        childWidth, 0, childWidth, childHeight);
+            }
+        });
+        countDownLatch1.await(500, TimeUnit.MILLISECONDS);
+
+        final CountDownLatch countDownLatch2 = new CountDownLatch(1);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                child1.setVisibility(View.GONE);
+                checkBounds(viewGroup, child2, countDownLatch2, 0, 0, childWidth, childHeight);
+            }
+        });
+        countDownLatch2.await(500, TimeUnit.MILLISECONDS);
+
+        final CountDownLatch countDownLatch3 = new CountDownLatch(2);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                child1.setVisibility(View.VISIBLE);
+                checkBounds(viewGroup, child1, countDownLatch3, 0, 0, childWidth, childHeight);
+                checkBounds(viewGroup, child2, countDownLatch3,
+                        childWidth, 0, childWidth, childHeight);
+            }
+        });
+        countDownLatch3.await(500, TimeUnit.MILLISECONDS);
+    }
+
     private class MockListView extends ListView {
         private final static int DEFAULT_CHILD_BASE_LINE = 1;
 
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/LinearLayout_LayoutParamsTest.java
index 31be765..4f36e94 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayout_LayoutParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import org.xmlpull.v1.XmlPullParserException;
 
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index c4636fc..5856910 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.app.Instrumentation;
diff --git a/tests/tests/widget/src/android/widget/cts/ListViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ListViewCtsActivity.java
index 186e47b..ce198b3 100644
--- a/tests/tests/widget/src/android/widget/cts/ListViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ListViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/ListViewTest.java b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
index 838f7a8..e311cc7 100644
--- a/tests/tests/widget/src/android/widget/cts/ListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -37,6 +37,7 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver.OnDrawListener;
 import android.view.animation.LayoutAnimationController;
 import android.widget.AbsListView;
 import android.widget.AdapterView;
@@ -69,7 +70,7 @@
     private ArrayAdapter<String> mAdapter_empty;
 
     public ListViewTest() {
-        super("com.android.cts.widget", ListViewCtsActivity.class);
+        super("android.widget.cts", ListViewCtsActivity.class);
     }
 
     protected void setUp() throws Exception {
@@ -137,8 +138,11 @@
     }
 
     public void testAccessDividerHeight() {
+        final HasDrawnListener drawListener = new HasDrawnListener();
+
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
+                mListView.getViewTreeObserver().addOnDrawListener(drawListener);
                 mListView.setAdapter(mAdapter_countries);
             }
         });
@@ -155,23 +159,44 @@
 
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
+                drawListener.reset();
                 mListView.setDividerHeight(20);
             }
         });
         mInstrumentation.waitForIdleSync();
+        assertTrue(drawListener.hasDrawn());
         assertEquals(20, mListView.getDividerHeight());
         assertEquals(20, r.bottom - r.top);
 
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
+                drawListener.reset();
                 mListView.setDividerHeight(10);
             }
         });
         mInstrumentation.waitForIdleSync();
+        assertTrue(drawListener.hasDrawn());
         assertEquals(10, mListView.getDividerHeight());
         assertEquals(10, r.bottom - r.top);
     }
 
+    static class HasDrawnListener implements OnDrawListener {
+        private boolean mHasDrawn;
+
+        @Override
+        public void onDraw() {
+            mHasDrawn = true;
+        }
+
+        public boolean hasDrawn() {
+            return mHasDrawn;
+        }
+
+        public void reset() {
+            mHasDrawn = false;
+        }
+    }
+
     public void testAccessItemsCanFocus() {
         mListView.setItemsCanFocus(true);
         assertTrue(mListView.getItemsCanFocus());
diff --git a/tests/tests/widget/src/android/widget/cts/MediaControllerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/MediaControllerCtsActivity.java
index 5dfcc59..ac8f100 100644
--- a/tests/tests/widget/src/android/widget/cts/MediaControllerCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/MediaControllerCtsActivity.java
@@ -20,7 +20,7 @@
 import android.os.Bundle;
 import android.widget.MediaController;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * A minimal application for {@link MediaController} test.
diff --git a/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java b/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
index 9f3aa55..713604d 100644
--- a/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -50,7 +50,7 @@
     private static final long DEFAULT_TIMEOUT = 3000;
 
     public MediaControllerTest() {
-        super("com.android.cts.widget", MediaControllerCtsActivity.class);
+        super("android.widget.cts", MediaControllerCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/MockPopupWindowCtsActivity.java b/tests/tests/widget/src/android/widget/cts/MockPopupWindowCtsActivity.java
index 9589fec..5d22fe5 100644
--- a/tests/tests/widget/src/android/widget/cts/MockPopupWindowCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/MockPopupWindowCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/MockURLSpanTestActivity.java b/tests/tests/widget/src/android/widget/cts/MockURLSpanTestActivity.java
index ab4940c..3d27f9a 100644
--- a/tests/tests/widget/src/android/widget/cts/MockURLSpanTestActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/MockURLSpanTestActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewCtsActivity.java
index 1379150..b5de67b 100644
--- a/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewTest.java b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewTest.java
index 4afdb80..5c18030 100644
--- a/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -44,7 +44,7 @@
     private Activity mActivity;
 
     public MultiAutoCompleteTextViewTest() {
-        super("com.android.cts.widget", MultiAutoCompleteTextViewCtsActivity.class);
+        super("android.widget.cts", MultiAutoCompleteTextViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index 2dff4cb..206b794 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
 import android.app.Instrumentation;
@@ -24,6 +24,7 @@
 import android.view.Gravity;
 import android.widget.PopupMenu;
 
+import android.widget.cts.R;
 
 public class PopupMenuTest extends
         ActivityInstrumentationTestCase2<MockPopupWindowCtsActivity> {
@@ -31,7 +32,7 @@
     private Activity mActivity;
 
     public PopupMenuTest() {
-        super("com.android.cts.widget", MockPopupWindowCtsActivity.class);
+        super("android.widget.cts", MockPopupWindowCtsActivity.class);
     }
 
     @Override
@@ -45,6 +46,7 @@
         PopupMenu popupMenu = new PopupMenu(mActivity,
                 mActivity.findViewById(R.id.anchor_middle_left));
         assertEquals(Gravity.NO_GRAVITY, popupMenu.getGravity());
+
         popupMenu.setGravity(Gravity.TOP);
         assertEquals(Gravity.TOP, popupMenu.getGravity());
     }
@@ -52,7 +54,7 @@
     public void testOnDismissListener() {
         final PopupMenu popupMenu = new PopupMenu(mActivity,
                 mActivity.findViewById(R.id.anchor_middle_left));
-        TestPopupDismissListener listener = new TestPopupDismissListener();
+        PopupMenu.OnDismissListener listener = mock(PopupMenu.OnDismissListener.class);
         popupMenu.setOnDismissListener(listener);
 
         mInstrumentation.runOnMainSync(new Runnable() {
@@ -61,7 +63,7 @@
             }
         });
         mInstrumentation.waitForIdleSync();
-        assertEquals(0, listener.getDismissCount());
+        verify(listener, never()).onDismiss(popupMenu);
 
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
@@ -69,7 +71,7 @@
             }
         });
         mInstrumentation.waitForIdleSync();
-        assertEquals(1, listener.getDismissCount());
+        verify(listener, times(1)).onDismiss(popupMenu);
 
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
@@ -77,19 +79,6 @@
             }
         });
         mInstrumentation.waitForIdleSync();
-        assertEquals(1, listener.getDismissCount());
-    }
-
-    private class TestPopupDismissListener implements PopupMenu.OnDismissListener {
-        int mDismissCount;
-
-        @Override
-        public void onDismiss(PopupMenu menu) {
-            mDismissCount++;
-        }
-
-        int getDismissCount() {
-            return mDismissCount;
-        }
+        verify(listener, times(1)).onDismiss(popupMenu);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index bb638e4..ff580e3 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -16,8 +16,9 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import static org.mockito.Mockito.*;
 
+import org.mockito.InOrder;
 
 import android.app.Activity;
 import android.app.Instrumentation;
@@ -25,24 +26,26 @@
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Debug;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.transition.Transition;
+import android.transition.Transition.TransitionListener;
 import android.transition.TransitionValues;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
 import android.widget.ImageView;
+import android.widget.PopupWindow.OnDismissListener;
 import android.widget.PopupWindow;
 import android.widget.TextView;
-import android.widget.PopupWindow.OnDismissListener;
+
+import android.widget.cts.R;
 
 public class PopupWindowTest extends
         ActivityInstrumentationTestCase2<MockPopupWindowCtsActivity> {
@@ -55,7 +58,7 @@
      * Instantiates a new popup window test.
      */
     public PopupWindowTest() {
-        super("com.android.cts.widget", MockPopupWindowCtsActivity.class);
+        super("android.widget.cts", MockPopupWindowCtsActivity.class);
     }
 
     /*
@@ -425,20 +428,20 @@
         mPopupWindow = new PopupWindow(new TextView(mActivity));
         mPopupWindow.setOnDismissListener(null);
 
-        MockOnDismissListener onDismissListener = new MockOnDismissListener();
+        OnDismissListener onDismissListener = mock(OnDismissListener.class);
         mPopupWindow.setOnDismissListener(onDismissListener);
         showPopup();
         dismissPopup();
-        assertEquals(1, onDismissListener.getOnDismissCalledCount());
+        verify(onDismissListener, times(1)).onDismiss();
 
         showPopup();
         dismissPopup();
-        assertEquals(2, onDismissListener.getOnDismissCalledCount());
+        verify(onDismissListener, times(2)).onDismiss();
 
         mPopupWindow.setOnDismissListener(null);
         showPopup();
         dismissPopup();
-        assertEquals(2, onDismissListener.getOnDismissCalledCount());
+        verify(onDismissListener, times(2)).onDismiss();
     }
 
     public void testUpdate() {
@@ -485,23 +488,34 @@
     }
 
     public void testEnterExitTransition() {
-        mPopupWindow = createPopupWindow(createPopupContent());
-        final View anchorView = mActivity.findViewById(R.id.anchor_upper);
+        TransitionListener enterListener = mock(TransitionListener.class);
+        Transition enterTransition = new BaseTransition();
+        enterTransition.addListener(enterListener);
 
-        final MockTransition enterTransition = new MockTransition();
-        final MockTransition exitTransition = new MockTransition();
+        TransitionListener exitListener = mock(TransitionListener.class);
+        Transition exitTransition = new BaseTransition();
+        enterTransition.addListener(enterListener);
+
+        OnDismissListener dismissListener = mock(OnDismissListener.class);
+
+        mPopupWindow = createPopupWindow(createPopupContent());
         mPopupWindow.setEnterTransition(enterTransition);
         mPopupWindow.setExitTransition(exitTransition);
+        mPopupWindow.setOnDismissListener(dismissListener);
+        verify(enterListener, never()).onTransitionStart(any(Transition.class));
+        verify(exitListener, never()).onTransitionStart(any(Transition.class));
+        verify(dismissListener, never()).onDismiss();
 
+        final View anchorView = mActivity.findViewById(R.id.anchor_upper);
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
                 mPopupWindow.showAsDropDown(anchorView, 0, 0);
             }
         });
         mInstrumentation.waitForIdleSync();
-
-        assertEquals(1, enterTransition.getTransitionCount());
-        assertEquals(0, exitTransition.getTransitionCount());
+        verify(enterListener, times(1)).onTransitionStart(enterTransition);
+        verify(exitListener, never()).onTransitionStart(any(Transition.class));
+        verify(dismissListener, never()).onDismiss();
 
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
@@ -509,9 +523,13 @@
             }
         });
         mInstrumentation.waitForIdleSync();
+        verify(enterListener, times(1)).onTransitionStart(enterTransition);
+        verify(exitListener, times(1)).onTransitionStart(exitTransition);
+        verify(dismissListener, times(1)).onDismiss();
 
-        assertEquals(1, enterTransition.getTransitionCount());
-        assertEquals(1, exitTransition.getTransitionCount());
+        InOrder inOrder = inOrder(exitListener, dismissListener);
+        inOrder.verify(exitListener).onTransitionEnd(exitTransition);
+        inOrder.verify(dismissListener).onDismiss();
     }
 
     public void testUpdatePositionAndDimension() {
@@ -774,7 +792,9 @@
     public void testSetTouchInterceptor() {
         mPopupWindow = new PopupWindow(new TextView(mActivity));
 
-        MockOnTouchListener onTouchListener = new MockOnTouchListener();
+        OnTouchListener onTouchListener = mock(OnTouchListener.class);
+        when(onTouchListener.onTouch(any(View.class), any(MotionEvent.class))).thenReturn(true);
+
         mPopupWindow.setTouchInterceptor(onTouchListener);
         mPopupWindow.setFocusable(true);
         mPopupWindow.setOutsideTouchable(true);
@@ -794,20 +814,20 @@
         MotionEvent event = MotionEvent.obtain(downTime, eventTime,
                 MotionEvent.ACTION_DOWN, x, y, 0);
         getInstrumentation().sendPointerSync(event);
-        assertEquals(1, onTouchListener.getOnTouchCalledCount());
+        verify(onTouchListener, times(1)).onTouch(any(View.class), any(MotionEvent.class));
 
         downTime = SystemClock.uptimeMillis();
         eventTime = SystemClock.uptimeMillis();
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
         getInstrumentation().sendPointerSync(event);
-        assertEquals(2, onTouchListener.getOnTouchCalledCount());
+        verify(onTouchListener, times(2)).onTouch(any(View.class), any(MotionEvent.class));
 
         mPopupWindow.setTouchInterceptor(null);
         downTime = SystemClock.uptimeMillis();
         eventTime = SystemClock.uptimeMillis();
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
         getInstrumentation().sendPointerSync(event);
-        assertEquals(2, onTouchListener.getOnTouchCalledCount());
+        verify(onTouchListener, times(2)).onTouch(any(View.class), any(MotionEvent.class));
     }
 
     public void testSetWindowLayoutMode() {
@@ -829,107 +849,12 @@
         assertEquals(LayoutParams.MATCH_PARENT, p.height);
     }
 
-    /**
-     * The listener interface for receiving OnDismiss events. The class that is
-     * interested in processing a OnDismiss event implements this interface, and
-     * the object created with that class is registered with a component using
-     * the component's <code>setOnDismissListener<code> method. When
-     * the OnDismiss event occurs, that object's appropriate
-     * method is invoked.
-     */
-    private static class MockOnDismissListener implements OnDismissListener {
+    private static class BaseTransition extends Transition {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {}
 
-        /** The Ondismiss called count. */
-        private int mOnDismissCalledCount;
-
-        /**
-         * Gets the onDismiss() called count.
-         *
-         * @return the on dismiss called count
-         */
-        public int getOnDismissCalledCount() {
-            return mOnDismissCalledCount;
-        }
-
-        /*
-         * (non-Javadoc)
-         *
-         * @see android.widget.PopupWindow.OnDismissListener#onDismiss()
-         */
-        public void onDismiss() {
-            mOnDismissCalledCount++;
-        }
-
-    }
-
-    /**
-     * The listener interface for receiving touch events.
-     */
-    private static class MockOnTouchListener implements OnTouchListener {
-
-        /** The onTouch called count. */
-        private int mOnTouchCalledCount;
-
-        /**
-         * Gets the onTouch() called count.
-         *
-         * @return the onTouch() called count
-         */
-        public int getOnTouchCalledCount() {
-            return mOnTouchCalledCount;
-        }
-
-        /*
-         * (non-Javadoc)
-         *
-         * @see android.widget.PopupWindow.OnTouchListener#onDismiss()
-         */
-        public boolean onTouch(View v, MotionEvent event) {
-            mOnTouchCalledCount++;
-            return true;
-        }
-    }
-
-    private static class MockTransition extends Transition {
-        private int mTransitionCount;
-
-        private MockTransition() {
-            addListener(new Transition.TransitionListener() {
-                @Override
-                public void onTransitionStart(Transition transition) {
-
-                }
-
-                public void onTransitionEnd(Transition transition) {
-                    mTransitionCount++;
-                }
-
-                @Override
-                public void onTransitionCancel(Transition transition) {
-
-                }
-
-                @Override
-                public void onTransitionPause(Transition transition) {
-
-                }
-
-                @Override
-                public void onTransitionResume(Transition transition) {
-
-                }
-            });
-        }
-
-        public void captureStartValues(TransitionValues transitionValues) {
-        }
-
-        public void captureEndValues(TransitionValues transitionValues) {
-        }
-
-        int getTransitionCount() {
-            return mTransitionCount;
-        }
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {}
     }
 
     private View createPopupContent() {
@@ -953,11 +878,6 @@
         return window;
     }
 
-    /**
-     * Show PopupWindow.
-     */
-    // FIXME: logcat info complains that there is window leakage due to that mPopupWindow is not
-    // clean up. Need to fix it.
     private void showPopup() {
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
@@ -972,14 +892,12 @@
         mInstrumentation.waitForIdleSync();
     }
 
-    /**
-     * Dismiss PopupWindow.
-     */
     private void dismissPopup() {
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
-                if (mPopupWindow == null || !mPopupWindow.isShowing())
+                if (mPopupWindow == null || !mPopupWindow.isShowing()) {
                     return;
+                }
                 mPopupWindow.dismiss();
             }
         });
diff --git a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
index e57d298..fd19191 100644
--- a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
@@ -21,7 +21,7 @@
 import android.graphics.PorterDuff;
 import android.view.LayoutInflater;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.content.Context;
diff --git a/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java b/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
index 4ec4eb5..eb9387b 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.content.Context;
diff --git a/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java b/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
index a172ecb..b2154e2 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
diff --git a/tests/tests/widget/src/android/widget/cts/RadioGroup_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/RadioGroup_LayoutParamsTest.java
index b14c0e8..37cd632 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioGroup_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioGroup_LayoutParamsTest.java
@@ -114,7 +114,7 @@
         }
 
         mLayoutParams = new LayoutParams(getContext(),
-                getAttributeSet(com.android.cts.widget.R.layout.radiogroup_1));
+                getAttributeSet(android.widget.cts.R.layout.radiogroup_1));
         assertNotNull(mLayoutParams);
         assertEquals(0.5, mLayoutParams.weight, 0);
         assertEquals(Gravity.BOTTOM, mLayoutParams.gravity);
@@ -131,7 +131,7 @@
 
         try {
             new RadioGroup.LayoutParams(null,
-                    getAttributeSet(com.android.cts.widget.R.layout.radiogroup_1));
+                    getAttributeSet(android.widget.cts.R.layout.radiogroup_1));
             fail("The constructor should throw NullPointerException when param Context is null.");
         } catch (NullPointerException e) {
         }
@@ -143,7 +143,7 @@
         assertEquals(LayoutParams.WRAP_CONTENT, layoutParams.width);
         assertEquals(LayoutParams.WRAP_CONTENT, layoutParams.height);
 
-        AttributeSet attrs = getAttributeSet(com.android.cts.widget.R.layout.radiogroup_1);
+        AttributeSet attrs = getAttributeSet(android.widget.cts.R.layout.radiogroup_1);
         TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
         layoutParams.setBaseAttributes(a,
                 R.styleable.ViewGroup_MarginLayout_layout_width,
diff --git a/tests/tests/widget/src/android/widget/cts/RatingBarCtsActivity.java b/tests/tests/widget/src/android/widget/cts/RatingBarCtsActivity.java
index 7d4e232..1a9cb40 100644
--- a/tests/tests/widget/src/android/widget/cts/RatingBarCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/RatingBarCtsActivity.java
@@ -19,7 +19,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * An application for ProgressBar test
diff --git a/tests/tests/widget/src/android/widget/cts/RatingBarTest.java b/tests/tests/widget/src/android/widget/cts/RatingBarTest.java
index 211d7fe..669e7a1 100644
--- a/tests/tests/widget/src/android/widget/cts/RatingBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RatingBarTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.content.Context;
 import android.test.ActivityInstrumentationTestCase2;
@@ -32,7 +32,7 @@
     private RatingBarCtsActivity mActivity;
 
     public RatingBarTest() {
-        super("com.android.cts.widget", RatingBarCtsActivity.class);
+        super("android.widget.cts", RatingBarCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/RelativeLayoutCtsActivity.java b/tests/tests/widget/src/android/widget/cts/RelativeLayoutCtsActivity.java
index df83f54..c394ca4 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayoutCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayoutCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
index b228ca6..cd3cb09 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -46,7 +46,7 @@
     private Activity mActivity;
 
     public RelativeLayoutTest() {
-        super("com.android.cts.widget", RelativeLayoutCtsActivity.class);
+        super("android.widget.cts", RelativeLayoutCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/RelativeLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/RelativeLayout_LayoutParamsTest.java
index 07c7b77..5706781 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayout_LayoutParamsTest.java
@@ -16,10 +16,11 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.ViewAsserts;
+import android.util.LayoutDirection;
 import android.view.View;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.RelativeLayout;
@@ -31,7 +32,7 @@
         ActivityInstrumentationTestCase2<RelativeLayoutCtsActivity> {
 
     public RelativeLayout_LayoutParamsTest() {
-        super("com.android.cts.widget", RelativeLayoutCtsActivity.class);
+        super("android.widget.cts", RelativeLayoutCtsActivity.class);
     }
 
     public void testConstructor() {
@@ -415,6 +416,29 @@
         assertEquals(Integer.MIN_VALUE, rules[RelativeLayout.ALIGN_LEFT]);
     }
 
+    public void testRemoveRule() {
+        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
+
+        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_START, RelativeLayout.TRUE);
+        layoutParams.resolveLayoutDirection(LayoutDirection.LTR);
+        assertEquals(0, layoutParams.getRule(RelativeLayout.ALIGN_PARENT_START));
+        assertEquals(RelativeLayout.TRUE, layoutParams.getRule(RelativeLayout.ALIGN_PARENT_LEFT));
+        assertEquals(0, layoutParams.getRule(RelativeLayout.CENTER_HORIZONTAL));
+
+        layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_START);
+        layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
+        layoutParams.resolveLayoutDirection(LayoutDirection.LTR);
+        assertEquals(0, layoutParams.getRule(RelativeLayout.ALIGN_PARENT_START));
+        assertEquals(0, layoutParams.getRule(RelativeLayout.ALIGN_PARENT_LEFT));
+        assertEquals(RelativeLayout.TRUE, layoutParams.getRule(RelativeLayout.CENTER_HORIZONTAL));
+
+        layoutParams.removeRule(RelativeLayout.CENTER_HORIZONTAL);
+        layoutParams.resolveLayoutDirection(LayoutDirection.LTR);
+        assertEquals(0, layoutParams.getRule(RelativeLayout.ALIGN_PARENT_START));
+        assertEquals(0, layoutParams.getRule(RelativeLayout.ALIGN_PARENT_LEFT));
+        assertEquals(0, layoutParams.getRule(RelativeLayout.CENTER_HORIZONTAL));
+    }
+
     public void testDebug() {
         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
         assertNotNull(layoutParams.debug("test: "));
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
index ab109b1..369d7aa 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
@@ -26,11 +26,11 @@
 import android.view.ViewGroup;
 import android.widget.RemoteViews;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 public class RemoteViewsActivityTest
         extends ActivityInstrumentationTestCase2<RemoteViewsCtsActivity> {
-    private static final String PACKAGE_NAME = "com.android.cts.widget";
+    private static final String PACKAGE_NAME = "android.widget.cts";
     private Activity mActivity;
 
     public RemoteViewsActivityTest() {
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsCtsActivity.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsCtsActivity.java
index 4da5aa2..64001dc 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.cts.util.NullWebViewUtils;
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index 18bac7e..605dbb6 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -18,7 +18,7 @@
 
 import android.graphics.drawable.Icon;
 import android.test.UiThreadTest;
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.app.Activity;
@@ -59,7 +59,7 @@
  * Test {@link RemoteViews}.
  */
 public class RemoteViewsTest extends ActivityInstrumentationTestCase2<RemoteViewsCtsActivity> {
-    private static final String PACKAGE_NAME = "com.android.cts.widget";
+    private static final String PACKAGE_NAME = "android.widget.cts";
 
     private static final int INVALD_ID = -1;
 
diff --git a/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
index 580be27..aefca0f 100644
--- a/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.content.Context;
diff --git a/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java
index 760f7e4..e801e93 100644
--- a/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.content.Context;
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ScrollViewCtsActivity.java
index 8965610..b2b51c6 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
index a8fb224..0119cc0 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -61,7 +61,7 @@
     private Activity mActivity;
 
     public ScrollViewTest() {
-        super("com.android.cts.widget", ScrollViewCtsActivity.class);
+        super("android.widget.cts", ScrollViewCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/SeekBarCtsActivity.java b/tests/tests/widget/src/android/widget/cts/SeekBarCtsActivity.java
index e7842c2..e22b910 100644
--- a/tests/tests/widget/src/android/widget/cts/SeekBarCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/SeekBarCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/SeekBarTest.java b/tests/tests/widget/src/android/widget/cts/SeekBarTest.java
index 43aada2..b9ad733 100644
--- a/tests/tests/widget/src/android/widget/cts/SeekBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SeekBarTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.app.Activity;
@@ -38,7 +38,7 @@
     private Instrumentation mInstrumentation;
 
     public SeekBarTest() {
-        super("com.android.cts.widget", SeekBarCtsActivity.class);
+        super("android.widget.cts", SeekBarCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
index 28ff15e..5a9af25 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
@@ -92,7 +92,7 @@
         mContext = getInstrumentation().getTargetContext();
         mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mAdapterHost = (LinearLayout) mInflater.inflate(
-                com.android.cts.widget.R.layout.cursoradapter_host, null);
+                android.widget.cts.R.layout.cursoradapter_host, null);
 
         // new the SimpleAdapter instance
         mSimpleAdapter = new SimpleAdapter(mContext,
@@ -289,9 +289,9 @@
         // String represents resId
         ImageView view = new ImageView(mContext);
         assertNull(view.getDrawable());
-        mSimpleAdapter.setViewImage(view, String.valueOf(com.android.cts.widget.R.drawable.scenery));
+        mSimpleAdapter.setViewImage(view, String.valueOf(android.widget.cts.R.drawable.scenery));
         BitmapDrawable d = (BitmapDrawable) mContext.getResources().getDrawable(
-                com.android.cts.widget.R.drawable.scenery);
+                android.widget.cts.R.drawable.scenery);
         WidgetTestUtils.assertEquals(d.getBitmap(),
                 ((BitmapDrawable) view.getDrawable()).getBitmap());
 
@@ -314,9 +314,9 @@
         // resId
         view = new ImageView(mContext);
         assertNull(view.getDrawable());
-        mSimpleAdapter.setViewImage(view, com.android.cts.widget.R.drawable.scenery);
+        mSimpleAdapter.setViewImage(view, android.widget.cts.R.drawable.scenery);
         d = (BitmapDrawable) mContext.getResources()
-                .getDrawable(com.android.cts.widget.R.drawable.scenery);
+                .getDrawable(android.widget.cts.R.drawable.scenery);
         WidgetTestUtils.assertEquals(d.getBitmap(),
                 ((BitmapDrawable) view.getDrawable()).getBitmap());
 
@@ -331,11 +331,11 @@
         assertNull(view.getDrawable());
         try {
             mSimpleAdapter.setViewImage(view, SimpleCursorAdapterTest.createTestImage(mContext,
-                    "testimage", com.android.cts.widget.R.raw.testimage));
+                    "testimage", android.widget.cts.R.raw.testimage));
             assertNotNull(view.getDrawable());
             Bitmap actualBitmap = ((BitmapDrawable) view.getDrawable()).getBitmap();
             Bitmap testBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(mContext.getResources(),
-                    com.android.cts.widget.R.raw.testimage, actualBitmap.getConfig());
+                    android.widget.cts.R.raw.testimage, actualBitmap.getConfig());
             WidgetTestUtils.assertEquals(testBitmap, actualBitmap);
         } finally {
             SimpleCursorAdapterTest.destroyTestImage(mContext,"testimage");
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
index 13184de..f7f24da 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.content.Context;
@@ -185,7 +185,7 @@
     public void testSetViewImage() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         // resId
-        int sceneryImgResId = com.android.cts.widget.R.drawable.scenery;
+        int sceneryImgResId = android.widget.cts.R.drawable.scenery;
         ImageView view = new ImageView(mContext);
         assertNull(view.getDrawable());
         simpleCursorAdapter.setViewImage(view, String.valueOf(sceneryImgResId));
@@ -216,7 +216,7 @@
         view = new ImageView(mContext);
         assertNull(view.getDrawable());
         try {
-            int testimgRawId = com.android.cts.widget.R.raw.testimage;
+            int testimgRawId = android.widget.cts.R.raw.testimage;
             simpleCursorAdapter.setViewImage(view,
                     createTestImage(mContext, SAMPLE_IMAGE_NAME, testimgRawId));
             assertNotNull(view.getDrawable());
@@ -327,7 +327,7 @@
         LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         ViewGroup viewGroup = (ViewGroup) layoutInflater.inflate(
-                com.android.cts.widget.R.layout.cursoradapter_host, null);
+                android.widget.cts.R.layout.cursoradapter_host, null);
         View result = simpleCursorAdapter.newView(mContext, null, viewGroup);
         assertNotNull(result);
         assertEquals(R.id.cursorAdapter_item0, result.getId());
@@ -343,7 +343,7 @@
         LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         ViewGroup viewGroup = (ViewGroup) layoutInflater.inflate(
-                com.android.cts.widget.R.layout.cursoradapter_host, null);
+                android.widget.cts.R.layout.cursoradapter_host, null);
         View result = simpleCursorAdapter.newDropDownView(null, null, viewGroup);
         assertNotNull(result);
         assertEquals(R.id.cursorAdapter_item0, result.getId());
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
index c9fdbc3..02941fa 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.content.Context;
@@ -136,9 +136,9 @@
         ImageView view = new ImageView(mContext);
         assertNull(view.getDrawable());
         mSimpleCursorTreeAdapter.setViewImage(view,
-                String.valueOf(com.android.cts.widget.R.drawable.scenery));
+                String.valueOf(android.widget.cts.R.drawable.scenery));
         BitmapDrawable d = (BitmapDrawable) mContext.getResources().getDrawable(
-                com.android.cts.widget.R.drawable.scenery);
+                android.widget.cts.R.drawable.scenery);
         WidgetTestUtils.assertEquals(d.getBitmap(),
                 ((BitmapDrawable) view.getDrawable()).getBitmap());
 
@@ -164,10 +164,10 @@
         try {
             mSimpleCursorTreeAdapter.setViewImage(view,
                     SimpleCursorAdapterTest.createTestImage(mContext, SAMPLE_IMAGE_NAME,
-                            com.android.cts.widget.R.raw.testimage));
+                            android.widget.cts.R.raw.testimage));
             Bitmap actualBitmap = ((BitmapDrawable) view.getDrawable()).getBitmap();
             Bitmap test = WidgetTestUtils.getUnscaledAndDitheredBitmap(mContext.getResources(),
-                    com.android.cts.widget.R.raw.testimage, actualBitmap.getConfig());
+                    android.widget.cts.R.raw.testimage, actualBitmap.getConfig());
             WidgetTestUtils.assertEquals(test, actualBitmap);
         } finally {
             SimpleCursorAdapterTest.destroyTestImage(mContext, SAMPLE_IMAGE_NAME);
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java
index d1c63c0..674f427 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java
@@ -98,7 +98,7 @@
 
         mAdapterHost = (LinearLayout) ((LayoutInflater) mContext
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
-                com.android.cts.widget.R.layout.cursoradapter_host, null);
+                android.widget.cts.R.layout.cursoradapter_host, null);
     }
 
     public void testConstructor() {
diff --git a/tests/tests/widget/src/android/widget/cts/SlidingDrawerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/SlidingDrawerCtsActivity.java
index 8b55e63..d1362c1 100644
--- a/tests/tests/widget/src/android/widget/cts/SlidingDrawerCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/SlidingDrawerCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java b/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
index 862fccf..2af1b06 100644
--- a/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -51,7 +51,7 @@
     private Object mLock;
 
     public SlidingDrawerTest() {
-        super("com.android.cts.widget", SlidingDrawerCtsActivity.class);
+        super("android.widget.cts", SlidingDrawerCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/SpinnerTest.java b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
index ea37470..eea1e3e 100644
--- a/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.app.AlertDialog;
@@ -37,7 +37,7 @@
     private Context mTargetContext;
 
     public SpinnerTest() {
-        super("com.android.cts.widget", RelativeLayoutCtsActivity.class);
+        super("android.widget.cts", RelativeLayoutCtsActivity.class);
     }
 
     @Override
@@ -77,7 +77,7 @@
 
         spinner = (Spinner) getActivity().findViewById(R.id.spinner1);
         ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mTargetContext,
-                com.android.cts.widget.R.array.string, android.R.layout.simple_spinner_item);
+                android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
         spinner.setAdapter(adapter);
         assertTrue(spinner.getBaseline() > 0);
diff --git a/tests/tests/widget/src/android/widget/cts/SwitchTest.java b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
index 164e7bf..e1124f3 100644
--- a/tests/tests/widget/src/android/widget/cts/SwitchTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.content.Context;
 import android.content.res.ColorStateList;
diff --git a/tests/tests/widget/src/android/widget/cts/TabHostCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TabHostCtsActivity.java
index 9703dd7..189dbee 100644
--- a/tests/tests/widget/src/android/widget/cts/TabHostCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/TabHostCtsActivity.java
@@ -22,7 +22,7 @@
 import android.widget.TabHost;
 import android.widget.TextView;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * A minimal application for TabHost test.
diff --git a/tests/tests/widget/src/android/widget/cts/TabHostTest.java b/tests/tests/widget/src/android/widget/cts/TabHostTest.java
index 00ecd40..0544c24 100644
--- a/tests/tests/widget/src/android/widget/cts/TabHostTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TabHostTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.app.Activity;
@@ -43,7 +43,7 @@
     private TabHostCtsActivity mActivity;
 
     public TabHostTest() {
-        super("com.android.cts.widget", TabHostCtsActivity.class);
+        super("android.widget.cts", TabHostCtsActivity.class);
     }
 
     @Override
@@ -72,7 +72,7 @@
      * 2. no exception occurs when doing normal operation after setup().
      */
     public void testSetup1() throws Throwable {
-        final Activity activity = launchActivity("com.android.cts.widget", CtsActivity.class, null);
+        final Activity activity = launchActivity("android.widget.cts", CtsActivity.class, null);
 
         runTestOnUiThread(new Runnable() {
             public void run() {
@@ -103,7 +103,7 @@
      * 2. no exception occurs when uses TabSpec.setContent(android.content.Intent) after setup().
      */
     public void testSetup2() throws Throwable {
-        final ActivityGroup activity = launchActivity("com.android.cts.widget",
+        final ActivityGroup activity = launchActivity("android.widget.cts",
                 ActivityGroup.class, null);
 
 
diff --git a/tests/tests/widget/src/android/widget/cts/TabHost_TabSpecTest.java b/tests/tests/widget/src/android/widget/cts/TabHost_TabSpecTest.java
index 5745808..e8825c7 100644
--- a/tests/tests/widget/src/android/widget/cts/TabHost_TabSpecTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TabHost_TabSpecTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.app.Activity;
@@ -46,7 +46,7 @@
     private TabHostCtsActivity mActivity;
 
     public TabHost_TabSpecTest() {
-        super("com.android.cts.widget", TabHostCtsActivity.class);
+        super("android.widget.cts", TabHostCtsActivity.class);
     }
 
     @Override
@@ -137,7 +137,7 @@
         TabSpec tabSpec2 = mTabHost.newTabSpec("tab spec 2");
         tabSpec2.setIndicator("tab 2");
         // TabContentFactory to create a TextView as the content of the tab.
-        tabSpec2.setContent(com.android.cts.widget.R.id.tabhost_textview);
+        tabSpec2.setContent(android.widget.cts.R.id.tabhost_textview);
         mTabHost.addTab(tabSpec2);
         mTabHost.setCurrentTab(1);
         TextView currentView = (TextView) mTabHost.getCurrentView();
@@ -147,7 +147,7 @@
         TabSpec tabSpec3 = mTabHost.newTabSpec("tab spec 3");
         tabSpec3.setIndicator("tab 3");
         // TabContentFactory to create a ListView as the content of the tab.
-        tabSpec3.setContent(com.android.cts.widget.R.id.tabhost_listview);
+        tabSpec3.setContent(android.widget.cts.R.id.tabhost_listview);
         mTabHost.addTab(tabSpec3);
         mTabHost.setCurrentTab(2);
         assertTrue(mTabHost.getCurrentView() instanceof ListView);
diff --git a/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java b/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java
index 1f2e66c..f44117a 100644
--- a/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java
@@ -36,7 +36,7 @@
     private Activity mActivity;
 
     public TabWidgetTest() {
-        super("com.android.cts.widget", TabHostCtsActivity.class);
+        super("android.widget.cts", TabHostCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/TableCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TableCtsActivity.java
index f76caed..490d261 100644
--- a/tests/tests/widget/src/android/widget/cts/TableCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/TableCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
index b9f0d1f..ccf22d9 100644
--- a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.content.Context;
 import android.content.res.XmlResourceParser;
@@ -42,7 +42,7 @@
     private Context mContext;
 
     public TableLayoutTest() {
-        super("com.android.cts.widget", TableCtsActivity.class);
+        super("android.widget.cts", TableCtsActivity.class);
     }
 
     @Override
@@ -58,14 +58,14 @@
         new TableLayout(mContext, null);
 
         TableCtsActivity activity = getActivity();
-        activity.setContentView(com.android.cts.widget.R.layout.table_layout_1);
+        activity.setContentView(android.widget.cts.R.layout.table_layout_1);
         TableLayout tableLayout = (TableLayout) activity
-                .findViewById(com.android.cts.widget.R.id.table1);
+                .findViewById(android.widget.cts.R.id.table1);
         assertTrue(tableLayout.isColumnCollapsed(0));
         assertTrue(tableLayout.isColumnStretchable(2));
 
-        activity.setContentView(com.android.cts.widget.R.layout.table_layout_2);
-        tableLayout = (TableLayout) activity.findViewById(com.android.cts.widget.R.id.table2);
+        activity.setContentView(android.widget.cts.R.layout.table_layout_2);
+        tableLayout = (TableLayout) activity.findViewById(android.widget.cts.R.id.table2);
         assertTrue(tableLayout.isColumnShrinkable(1));
     }
 
@@ -205,12 +205,12 @@
         final TableCtsActivity activity = getActivity();
         getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
-                activity.setContentView(com.android.cts.widget.R.layout.table_layout_1);
+                activity.setContentView(android.widget.cts.R.layout.table_layout_1);
             }
         });
         getInstrumentation().waitForIdleSync();
         final TableLayout tableLayout =
-                (TableLayout) activity.findViewById(com.android.cts.widget.R.id.table1);
+                (TableLayout) activity.findViewById(android.widget.cts.R.id.table1);
 
         // Preparation: remove Collapsed mark for column 0.
         getInstrumentation().runOnMainSync(new Runnable() {
diff --git a/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
index cbc41ce..fbd9f97 100644
--- a/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 
diff --git a/tests/tests/widget/src/android/widget/cts/TableRowTest.java b/tests/tests/widget/src/android/widget/cts/TableRowTest.java
index 6012f59..2e917f8 100644
--- a/tests/tests/widget/src/android/widget/cts/TableRowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableRowTest.java
@@ -33,7 +33,7 @@
 import android.widget.TableRow;
 import android.widget.TextView;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 /**
@@ -44,7 +44,7 @@
     Context mTargetContext;
 
     public TableRowTest() {
-        super("com.android.cts.widget", TableCtsActivity.class);
+        super("android.widget.cts", TableCtsActivity.class);
     }
 
     @Override
@@ -83,9 +83,9 @@
     @UiThreadTest
     public void testGetVirtualChildAt() {
         TableCtsActivity activity = getActivity();
-        activity.setContentView(com.android.cts.widget.R.layout.table_layout_1);
+        activity.setContentView(android.widget.cts.R.layout.table_layout_1);
         TableLayout tableLayout = (TableLayout) activity
-                .findViewById(com.android.cts.widget.R.id.table1);
+                .findViewById(android.widget.cts.R.id.table1);
 
         TableRow tableRow = (TableRow) tableLayout.getChildAt(0);
         Resources resources = activity.getResources();
@@ -96,8 +96,8 @@
         assertEquals(resources.getString(R.string.table_layout_third),
                 ((TextView) tableRow.getVirtualChildAt(2)).getText().toString());
 
-        activity.setContentView(com.android.cts.widget.R.layout.table_layout_2);
-        tableLayout = (TableLayout) activity.findViewById(com.android.cts.widget.R.id.table2);
+        activity.setContentView(android.widget.cts.R.layout.table_layout_2);
+        tableLayout = (TableLayout) activity.findViewById(android.widget.cts.R.id.table2);
 
         tableRow = (TableRow) tableLayout.getChildAt(0);
         assertNull(tableRow.getVirtualChildAt(0));
@@ -114,15 +114,15 @@
     @UiThreadTest
     public void testGetVirtualChildCount() {
         TableCtsActivity activity = getActivity();
-        activity.setContentView(com.android.cts.widget.R.layout.table_layout_1);
+        activity.setContentView(android.widget.cts.R.layout.table_layout_1);
         TableLayout tableLayout = (TableLayout) activity
-                .findViewById(com.android.cts.widget.R.id.table1);
+                .findViewById(android.widget.cts.R.id.table1);
 
         TableRow tableRow = (TableRow) tableLayout.getChildAt(0);
         assertEquals(3, tableRow.getVirtualChildCount());
 
-        activity.setContentView(com.android.cts.widget.R.layout.table_layout_2);
-        tableLayout = (TableLayout) activity.findViewById(com.android.cts.widget.R.id.table2);
+        activity.setContentView(android.widget.cts.R.layout.table_layout_2);
+        tableLayout = (TableLayout) activity.findViewById(android.widget.cts.R.id.table2);
 
         tableRow = (TableRow) tableLayout.getChildAt(0);
         assertEquals(5, tableRow.getVirtualChildCount());
diff --git a/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
index 8308414..ce3be70 100644
--- a/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -42,7 +42,7 @@
     Context mTargetContext;
 
     public TableRow_LayoutParamsTest() {
-        super("com.android.cts.widget", TableCtsActivity.class);
+        super("android.widget.cts", TableCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TextViewCtsActivity.java
index 888f215..31fc486 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 829171c..6a36c7e 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -16,7 +16,9 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.text.Html;
+import android.text.Spanned;
+import android.widget.cts.R;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -75,6 +77,7 @@
 import android.text.style.URLSpan;
 import android.text.util.Linkify;
 import android.util.DisplayMetrics;
+import android.util.LocaleList;
 import android.util.TypedValue;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -121,7 +124,7 @@
     private CharSequence mTransformedText;
 
     public TextViewTest() {
-        super("com.android.cts.widget", TextViewCtsActivity.class);
+        super("android.widget.cts", TextViewCtsActivity.class);
     }
 
     @Override
@@ -1266,6 +1269,50 @@
         }
     }
 
+    @UiThreadTest
+    public void testSetText_setsMovementMethodWhenLinksClickableAndTextContainsClickableSpans() {
+        Spanned text = Html.fromHtml("<a href='http://android.com'>link</a>");
+        mTextView = new TextView(mActivity);
+
+        mTextView.setLinksClickable(false);
+        mTextView.setText(text);
+        assertNull("TextView.setText should not set movement method if linksClickable is false",
+                mTextView.getMovementMethod());
+
+        mTextView.setLinksClickable(true);
+        mTextView.setText(text);
+        assertNotNull("TextView.setText should set movement method if linksClickable is true " +
+                "and text contains clickable spans", mTextView.getMovementMethod());
+    }
+
+    public void testRemoveSelectionWithSelectionHandles() {
+        initTextViewForTyping();
+
+        mActivity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTextView.setTextIsSelectable(true);
+                mTextView.setText("abcd", BufferType.EDITABLE);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Long click on the text selects all text and shows selection handlers. The view has an
+        // attribute layout_width="wrap_content", so clicked location (the center of the view)
+        // should be on the text.
+        TouchUtils.longClickView(this, mTextView);
+
+        mActivity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Selection.removeSelection((Spannable) mTextView.getText());
+            }
+        });
+
+        // Make sure that a crash doesn't happen with {@link Selection#removeSelection}.
+        mInstrumentation.waitForIdleSync();
+    }
+
     public void testUndo_insert() {
         initTextViewForTyping();
 
@@ -1699,6 +1746,64 @@
         mInstrumentation.waitForIdleSync();
     }
 
+    public void testCopyAndPaste_byKey() {
+        initTextViewForTyping();
+
+        // Type "abc".
+        mInstrumentation.sendStringSync("abc");
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Select "bc"
+                Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        // Copy "bc"
+        sendKeys(KeyEvent.KEYCODE_COPY);
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Set cursor between 'b' and 'c'.
+                Selection.setSelection((Spannable) mTextView.getText(), 2, 2);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        // Paste "bc"
+        sendKeys(KeyEvent.KEYCODE_PASTE);
+        assertEquals("abbcc", mTextView.getText().toString());
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                Selection.selectAll((Spannable) mTextView.getText());
+                KeyEvent copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+                        KeyEvent.KEYCODE_COPY, 0, KeyEvent.META_SHIFT_LEFT_ON);
+                // Shift + copy doesn't perform copy.
+                mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
+                Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+                mTextView.onTextContextMenuItem(android.R.id.paste);
+                assertEquals("bcabbcc", mTextView.getText().toString());
+
+                Selection.selectAll((Spannable) mTextView.getText());
+                copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_COPY, 0,
+                        KeyEvent.META_CTRL_LEFT_ON);
+                // Control + copy doesn't perform copy.
+                mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
+                Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+                mTextView.onTextContextMenuItem(android.R.id.paste);
+                assertEquals("bcbcabbcc", mTextView.getText().toString());
+
+                Selection.selectAll((Spannable) mTextView.getText());
+                copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_COPY, 0,
+                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_CTRL_LEFT_ON);
+                // Control + Shift + copy doesn't perform copy.
+                mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
+                Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+                mTextView.onTextContextMenuItem(android.R.id.paste);
+                assertEquals("bcbcbcabbcc", mTextView.getText().toString());
+            }
+        });
+    }
+
     public void testCutAndPaste() {
         initTextViewForTyping();
         mActivity.runOnUiThread(new Runnable() {
@@ -1724,6 +1829,57 @@
         mInstrumentation.waitForIdleSync();
     }
 
+    public void testCutAndPaste_byKey() {
+        initTextViewForTyping();
+
+        // Type "abc".
+        mInstrumentation.sendStringSync("abc");
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Select "bc"
+                Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        // Cut "bc"
+        sendKeys(KeyEvent.KEYCODE_CUT);
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                assertEquals("a", mTextView.getText().toString());
+                // Move cursor to the head
+                Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        // Paste "bc"
+        sendKeys(KeyEvent.KEYCODE_PASTE);
+        assertEquals("bca", mTextView.getText().toString());
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                Selection.selectAll((Spannable) mTextView.getText());
+                KeyEvent cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+                        KeyEvent.KEYCODE_CUT, 0, KeyEvent.META_SHIFT_LEFT_ON);
+                // Shift + cut doesn't perform cut.
+                mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
+                assertEquals("bca", mTextView.getText().toString());
+
+                cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_CUT, 0,
+                        KeyEvent.META_CTRL_LEFT_ON);
+                // Control + cut doesn't perform cut.
+                mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
+                assertEquals("bca", mTextView.getText().toString());
+
+                cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_CUT, 0,
+                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_CTRL_LEFT_ON);
+                // Control + Shift + cut doesn't perform cut.
+                mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
+                assertEquals("bca", mTextView.getText().toString());
+            }
+        });
+    }
+
     private static boolean hasSpansAtMiddleOfText(final TextView textView, final Class<?> type) {
         final Spannable spannable = (Spannable)textView.getText();
         final int at = spannable.length() / 2;
@@ -2427,6 +2583,160 @@
         }
     }
 
+    @UiThreadTest
+    public void testAppend_doesNotAddLinksWhenAppendedTextDoesNotContainLinks() {
+        mTextView = new TextView(mActivity);
+        mTextView.setAutoLinkMask(Linkify.ALL);
+        mTextView.setText("text without URL");
+
+        mTextView.append(" another text without URL");
+
+        Spannable text = (Spannable) mTextView.getText();
+        URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+        assertEquals("URLSpan count should be zero", 0, urlSpans.length);
+        assertEquals("text without URL another text without URL", text.toString());
+    }
+
+    @UiThreadTest
+    public void testAppend_doesNotAddLinksWhenAutoLinkIsNotEnabled() {
+        mTextView = new TextView(mActivity);
+        mTextView.setText("text without URL");
+
+        mTextView.append(" text with URL http://android.com");
+
+        Spannable text = (Spannable) mTextView.getText();
+        URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+        assertEquals("URLSpan count should be zero", 0, urlSpans.length);
+        assertEquals("text without URL text with URL http://android.com", text.toString());
+    }
+
+    @UiThreadTest
+    public void testAppend_addsLinksWhenAutoLinkIsEnabled() {
+        mTextView = new TextView(mActivity);
+        mTextView.setAutoLinkMask(Linkify.ALL);
+        mTextView.setText("text without URL");
+
+        mTextView.append(" text with URL http://android.com");
+
+        Spannable text = (Spannable) mTextView.getText();
+        URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+        assertEquals("URLSpan count should be one after appending a URL", 1, urlSpans.length);
+        assertEquals("URLSpan URL should be same as the appended URL",
+                urlSpans[0].getURL(), "http://android.com");
+        assertEquals("text without URL text with URL http://android.com", text.toString());
+    }
+
+    @UiThreadTest
+    public void testAppend_addsLinksEvenWhenThereAreUrlsSetBefore() {
+        mTextView = new TextView(mActivity);
+        mTextView.setAutoLinkMask(Linkify.ALL);
+        mTextView.setText("text with URL http://android.com/before");
+
+        mTextView.append(" text with URL http://android.com");
+
+        Spannable text = (Spannable) mTextView.getText();
+        URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+        assertEquals("URLSpan count should be two after appending another URL", 2, urlSpans.length);
+        assertEquals("First URLSpan URL should be same",
+                urlSpans[0].getURL(), "http://android.com/before");
+        assertEquals("URLSpan URL should be same as the appended URL",
+                urlSpans[1].getURL(), "http://android.com");
+        assertEquals("text with URL http://android.com/before text with URL http://android.com",
+                text.toString());
+    }
+
+    @UiThreadTest
+    public void testAppend_setsMovementMethodWhenTextContainsUrlAndAutoLinkIsEnabled() {
+        mTextView = new TextView(mActivity);
+        mTextView.setAutoLinkMask(Linkify.ALL);
+        mTextView.setText("text without a URL");
+
+        mTextView.append(" text with a url: http://android.com");
+
+        assertNotNull("MovementMethod should not be null when text contains url",
+                mTextView.getMovementMethod());
+        assertTrue("MovementMethod should be instance of LinkMovementMethod when text contains url",
+                mTextView.getMovementMethod() instanceof LinkMovementMethod);
+    }
+
+    @UiThreadTest
+    public void testAppend_setsMovementMethodWhenLinksClickableAndTextContainsClickableSpans() {
+        Spanned text = Html.fromHtml("<a href='http://android.com'>link</a>");
+        mTextView = new TextView(mActivity);
+
+        mTextView.setLinksClickable(false);
+        mTextView.append(text);
+        assertNull("TextView.append should not set movement method if linksClickable is false",
+                mTextView.getMovementMethod());
+
+        mTextView.setText("");
+        mTextView.setLinksClickable(true);
+        mTextView.append(text);
+        assertNotNull("TextView.append should set movement method if linksClickable is true " +
+                "and text contains clickable spans", mTextView.getMovementMethod());
+    }
+
+    @UiThreadTest
+    public void testAppend_setMovementMethodForExistingTextWhenLinksClickableIsTrueDuringAppend() {
+        Spanned text = Html.fromHtml("<a href='http://android.com'>link</a>");
+        mTextView = new TextView(mActivity);
+        mTextView.setLinksClickable(false);
+        mTextView.setText(text);
+
+        mTextView.setLinksClickable(true);
+        mTextView.append("");
+
+        assertNotNull("TextView.append should set movement method if existing text contains " +
+                "links but new text does not", mTextView.getMovementMethod());
+    }
+
+    @UiThreadTest
+    public void testAppend_addsLinksWhenTextIsSpannableAndContainsUrlAndAutoLinkIsEnabled() {
+        mTextView = new TextView(mActivity);
+        mTextView.setAutoLinkMask(Linkify.ALL);
+        mTextView.setText("text without a URL");
+
+        mTextView.append(new SpannableString(" text with a url: http://android.com"));
+
+        Spannable text = (Spannable) mTextView.getText();
+        URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+        assertEquals("URLSpan count should be one after appending a URL", 1, urlSpans.length);
+        assertEquals("URLSpan URL should be same as the appended URL",
+                urlSpans[0].getURL(), "http://android.com");
+    }
+
+    @UiThreadTest
+    public void testAppend_addsLinkIfAppendedTextCompletesPartialUrlAtTheEndOfExistingText() {
+        mTextView = new TextView(mActivity);
+        mTextView.setAutoLinkMask(Linkify.ALL);
+        mTextView.setText("text with a partial url android.");
+
+        mTextView.append("com");
+
+        Spannable text = (Spannable) mTextView.getText();
+        URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+        assertEquals("URLSpan count should be one after appending to partial URL",
+                1, urlSpans.length);
+        assertEquals("URLSpan URL should be same as the appended URL",
+                urlSpans[0].getURL(), "http://android.com");
+    }
+
+    @UiThreadTest
+    public void testAppend_addsLinkIfAppendedTextUpdatesUrlAtTheEndOfExistingText() {
+        mTextView = new TextView(mActivity);
+        mTextView.setAutoLinkMask(Linkify.ALL);
+        mTextView.setText("text with a url http://android.com");
+
+        mTextView.append("/textview");
+
+        Spannable text = (Spannable) mTextView.getText();
+        URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+        assertEquals("URLSpan count should still be one after extending a URL", 1, urlSpans.length);
+        assertEquals("URLSpan URL should be same as the new URL",
+                urlSpans[0].getURL(), "http://android.com/textview");
+    }
+
+
     public void testAccessTransformationMethod() {
         // check the password attribute in xml
         mTextView = findTextView(R.id.textview_password);
@@ -4026,6 +4336,41 @@
         }
     }
 
+    public void testTextLocales() {
+        TextView tv = new TextView(mActivity);
+        assertEquals(Locale.getDefault(), tv.getTextLocale());
+        assertEquals(LocaleList.getDefault(), tv.getTextLocales());
+
+        tv.setTextLocale(Locale.CHINESE);
+        assertEquals(Locale.CHINESE, tv.getTextLocale());
+        assertEquals(new LocaleList(Locale.CHINESE), tv.getTextLocales());
+
+        tv.setTextLocales(LocaleList.forLanguageTags("en,ja"));
+        assertEquals(Locale.forLanguageTag("en"), tv.getTextLocale());
+        assertEquals(LocaleList.forLanguageTags("en,ja"), tv.getTextLocales());
+
+        try {
+            tv.setTextLocale(null);
+            fail("Setting the text locale to null should throw");
+        } catch (Throwable e) {
+            assertEquals(IllegalArgumentException.class, e.getClass());
+        }
+
+        try {
+            tv.setTextLocales(null);
+            fail("Setting the text locales to null should throw");
+        } catch (Throwable e) {
+            assertEquals(IllegalArgumentException.class, e.getClass());
+        }
+
+        try {
+            tv.setTextLocales(new LocaleList());
+            fail("Setting the text locale to an empty list should throw");
+        } catch (Throwable e) {
+            assertEquals(IllegalArgumentException.class, e.getClass());
+        }
+    }
+
     public void testAllCapsLocalization() {
         String testString = "abcdefghijklmnopqrstuvwxyz";
 
diff --git a/tests/tests/widget/src/android/widget/cts/TimePickerTest.java b/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
index 1ce2844..39554bb 100644
--- a/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
@@ -39,7 +39,7 @@
     private Instrumentation mInstrumentation;
 
     public TimePickerTest() {
-        super("com.android.cts.widget", CtsActivity.class);
+        super("android.widget.cts", CtsActivity.class);
     }
 
     @Override
@@ -52,7 +52,7 @@
 
     public void testConstructors() {
         AttributeSet attrs =
-            mContext.getResources().getLayout(com.android.cts.widget.R.layout.timepicker);
+            mContext.getResources().getLayout(android.widget.cts.R.layout.timepicker);
         assertNotNull(attrs);
 
         new TimePicker(mContext);
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index 90a161e..854247e 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.app.Activity;
@@ -44,7 +44,7 @@
     private ViewTreeObserver.OnGlobalLayoutListener mLayoutListener;
 
     public ToastTest() {
-        super("com.android.cts.widget", CtsActivity.class);
+        super("android.widget.cts", CtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/ToggleButtonTest.java b/tests/tests/widget/src/android/widget/cts/ToggleButtonTest.java
index b3bc31e..d335c13 100644
--- a/tests/tests/widget/src/android/widget/cts/ToggleButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToggleButtonTest.java
@@ -21,13 +21,14 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
 import android.test.InstrumentationTestCase;
 import android.test.UiThreadTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.widget.ToggleButton;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 /**
@@ -96,9 +97,13 @@
         // drawableStateChanged without any drawable.
         toggleButton.drawableStateChanged();
 
+        StateListDrawable drawable = new StateListDrawable();
+        drawable.addState(new int[] { android.R.attr.state_pressed },
+                mContext.getDrawable(R.drawable.scenery));
+        drawable.addState(new int[] {},
+                mContext.getDrawable(R.drawable.scenery));
+
         // drawableStateChanged when CheckMarkDrawable is not null.
-        Resources resources = mContext.getResources();
-        Drawable drawable = resources.getDrawable(R.drawable.scenery);
         toggleButton.setButtonDrawable(drawable);
         drawable.setState(null);
         assertNull(drawable.getState());
diff --git a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
new file mode 100644
index 0000000..6bbcd4c
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 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.widget.cts;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.UiThreadTest;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Toolbar;
+
+public class ToolbarTest extends AndroidTestCase {
+    private Context mContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mContext = getContext();
+    }
+
+    @UiThreadTest
+    public void testGetTitleMargins() {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        View layout = inflater.inflate(R.layout.toolbar_layout, null);
+        Toolbar toolbar = (Toolbar) layout.findViewById(R.id.toolbar);
+
+        assertEquals(5, toolbar.getTitleMarginStart());
+        assertEquals(10, toolbar.getTitleMarginTop());
+        assertEquals(15, toolbar.getTitleMarginEnd());
+        assertEquals(20, toolbar.getTitleMarginBottom());
+    }
+
+    @UiThreadTest
+    public void testSetTitleMargins() {
+        Toolbar toolbar = new Toolbar(mContext);
+        assertEquals(0, toolbar.getTitleMarginStart());
+        assertEquals(0, toolbar.getTitleMarginTop());
+        assertEquals(0, toolbar.getTitleMarginEnd());
+        assertEquals(0, toolbar.getTitleMarginBottom());
+
+        toolbar.setTitleMargin(5, 10, 15, 20);
+        assertEquals(5, toolbar.getTitleMarginStart());
+        assertEquals(10, toolbar.getTitleMarginTop());
+        assertEquals(15, toolbar.getTitleMarginEnd());
+        assertEquals(20, toolbar.getTitleMarginBottom());
+
+        toolbar.setTitleMarginStart(25);
+        toolbar.setTitleMarginTop(30);
+        toolbar.setTitleMarginEnd(35);
+        toolbar.setTitleMarginBottom(40);
+        assertEquals(25, toolbar.getTitleMarginStart());
+        assertEquals(30, toolbar.getTitleMarginTop());
+        assertEquals(35, toolbar.getTitleMarginEnd());
+        assertEquals(40, toolbar.getTitleMarginBottom());
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/TwoLineListItemCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TwoLineListItemCtsActivity.java
index bd2c36d..68413ff 100644
--- a/tests/tests/widget/src/android/widget/cts/TwoLineListItemCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/TwoLineListItemCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/TwoLineListItemTest.java b/tests/tests/widget/src/android/widget/cts/TwoLineListItemTest.java
index 18dd407..4ee22a1 100644
--- a/tests/tests/widget/src/android/widget/cts/TwoLineListItemTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TwoLineListItemTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import android.app.Activity;
@@ -36,7 +36,7 @@
     private Activity mActivity;
 
     public TwoLineListItemTest() {
-        super("com.android.cts.widget", TwoLineListItemCtsActivity.class);
+        super("android.widget.cts", TwoLineListItemCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/VideoViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/VideoViewCtsActivity.java
index ad0d6eb..e831f04 100644
--- a/tests/tests/widget/src/android/widget/cts/VideoViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/VideoViewCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/VideoViewTest.java b/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
index d9af514..157bad8 100644
--- a/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.app.Instrumentation;
@@ -108,7 +108,7 @@
      * Instantiates a new video view test.
      */
     public VideoViewTest() {
-        super("com.android.cts.widget", VideoViewCtsActivity.class);
+        super("android.widget.cts", VideoViewCtsActivity.class);
     }
 
     /**
diff --git a/tests/tests/widget/src/android/widget/cts/ViewAnimatorCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ViewAnimatorCtsActivity.java
index 21deef7..ec3e59e 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewAnimatorCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewAnimatorCtsActivity.java
@@ -18,7 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 /**
  * A minimal application for ViewAnimator test.
diff --git a/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java b/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java
index 024e3ee..696761b 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -43,7 +43,7 @@
     private AttributeSet mAttributeSet;
 
     public ViewAnimatorTest() {
-        super("com.android.cts.widget", ViewAnimatorCtsActivity.class);
+        super("android.widget.cts", ViewAnimatorCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/ViewFlipperCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ViewFlipperCtsActivity.java
index 7f13f6c..ba90590 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewFlipperCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewFlipperCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/ViewFlipperTest.java b/tests/tests/widget/src/android/widget/cts/ViewFlipperTest.java
index 025fae4..5ec242e 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewFlipperTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewFlipperTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -37,7 +37,7 @@
     private Activity mActivity;
 
     public ViewFlipperTest() {
-        super("com.android.cts.widget", ViewFlipperCtsActivity.class);
+        super("android.widget.cts", ViewFlipperCtsActivity.class);
     }
 
     protected void setUp() throws Exception {
diff --git a/tests/tests/widget/src/android/widget/cts/ViewGroupCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ViewGroupCtsActivity.java
index 4e14fc2..f3b3a3e 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewGroupCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewGroupCtsActivity.java
@@ -35,8 +35,8 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(com.android.cts.widget.R.layout.viewgrouptest_stub);
-        TextView textView = (TextView)findViewById(com.android.cts.widget.R.id.viewgrouptest_stub);
+        setContentView(android.widget.cts.R.layout.viewgrouptest_stub);
+        TextView textView = (TextView)findViewById(android.widget.cts.R.id.viewgrouptest_stub);
         textView.setText("test");
     }
 
@@ -49,7 +49,7 @@
             mHandler.postDelayed(new Runnable() {
                 public void run() {
                     MockLinearLayout mll =
-                        (MockLinearLayout) findViewById(com.android.cts.widget.R.id.
+                        (MockLinearLayout) findViewById(android.widget.cts.R.id.
                                                                         mocklinearlayout);
                     if (!mll.mIsInvalidateChildInParentCalled) {
                         fail();
diff --git a/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java b/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java
index ce18267..7828570 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java
@@ -28,7 +28,7 @@
 import android.widget.ViewSwitcher;
 import android.widget.ViewSwitcher.ViewFactory;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 /**
diff --git a/tests/tests/widget/src/android/widget/cts/ZoomButtonCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ZoomButtonCtsActivity.java
index e371b3f..28563f5 100644
--- a/tests/tests/widget/src/android/widget/cts/ZoomButtonCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ZoomButtonCtsActivity.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
index 3d906db..493c484 100644
--- a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.cts.widget.R;
+import android.widget.cts.R;
 
 
 import org.xmlpull.v1.XmlPullParser;
@@ -37,7 +37,7 @@
     private Activity mActivity;
 
     public ZoomButtonTest() {
-        super("com.android.cts.widget", ZoomButtonCtsActivity.class);
+        super("android.widget.cts", ZoomButtonCtsActivity.class);
     }
 
     @Override
diff --git a/tests/tvprovider/Android.mk b/tests/tvprovider/Android.mk
new file mode 100644
index 0000000..acf4bb9
--- /dev/null
+++ b/tests/tvprovider/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsTvProviderTestCases
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
+
diff --git a/tests/tvprovider/AndroidManifest.xml b/tests/tvprovider/AndroidManifest.xml
new file mode 100644
index 0000000..fcf0ec5
--- /dev/null
+++ b/tests/tvprovider/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.tvprovider.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
+    <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="android.tvprovider.cts"
+            android:label="CTS tests for TV Provider" />
+</manifest>
diff --git a/tests/tvprovider/AndroidTest.xml b/tests/tvprovider/AndroidTest.xml
new file mode 100644
index 0000000..f92b37d
--- /dev/null
+++ b/tests/tvprovider/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS TV Provider test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTvProviderTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.tvprovider.cts" />
+    </test>
+</configuration>
diff --git a/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java b/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
new file mode 100644
index 0000000..b5fa019
--- /dev/null
+++ b/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
@@ -0,0 +1,379 @@
+/*
+ * 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.tvprovider.cts;
+
+import android.content.ComponentName;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.OperationApplicationException;
+import android.content.pm.PackageManager;
+import android.cts.util.CtsAndroidTestCase;
+import android.database.Cursor;
+import android.media.tv.TvContract;
+import android.media.tv.TvContract.Channels;
+import android.media.tv.TvContract.Programs;
+import android.net.Uri;
+import android.os.RemoteException;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.MeasureRun;
+import com.android.compatibility.common.util.MeasureTime;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+import com.android.cts.util.TimeoutReq;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test performance of TvProvider on a device. TvProvider typically handles hundreds of
+ * thousands of records periodically, so it is desirable to have performance under a reasonable
+ * bar.
+ */
+public class TvProviderPerfTest extends CtsAndroidTestCase {
+    private static final int TRANSACTION_RUNS = 100;
+    private static final int QUERY_RUNS = 10;
+
+    private ContentResolver mContentResolver;
+    private String mInputId;
+    private boolean mHasTvInputFramework;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mHasTvInputFramework = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_LIVE_TV);
+        if (!mHasTvInputFramework) return;
+        mContentResolver = getContext().getContentResolver();
+        mInputId = TvContract.buildInputId(new ComponentName(getContext(), getClass()));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            if (!mHasTvInputFramework) return;
+            mContentResolver.delete(Programs.CONTENT_URI, null, null);
+            mContentResolver.delete(Channels.CONTENT_URI, null, null);
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    @TimeoutReq(minutes = 8)
+    public void testChannels() throws Exception {
+        if (!mHasTvInputFramework) return;
+        double[] averages = new double[5];
+
+        // Insert
+        final ArrayList<ContentProviderOperation> operations = new ArrayList<>();
+        final int TRANSACTION_SIZE = 1000;
+        double[] applyBatchTimes = MeasureTime.measure(TRANSACTION_RUNS, new MeasureRun() {
+            @Override
+            public void run(int i) {
+                operations.clear();
+                for (int j = 0; j < TRANSACTION_SIZE; ++j) {
+                    ContentValues values = new ContentValues();
+                    values.put(Channels.COLUMN_INPUT_ID, mInputId);
+                    values.put(Channels.COLUMN_SERVICE_TYPE,
+                            Channels.SERVICE_TYPE_AUDIO_VIDEO);
+                    values.put(Channels.COLUMN_TYPE, Channels.TYPE_OTHER);
+                    operations.add(
+                            ContentProviderOperation.newInsert(Channels.CONTENT_URI)
+                            .withValues(values).build());
+                }
+                try {
+                    mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
+                } catch (OperationApplicationException | RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        });
+        DeviceReportLog report = new DeviceReportLog();
+        report.addValues("Elapsed time for insert: ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[0] = Stat.getAverage(applyBatchTimes);
+
+        // Update
+        final String[] projection = { Channels._ID };
+        try (final Cursor cursor = mContentResolver.query(Channels.CONTENT_URI,
+                projection, null, null, null)) {
+            applyBatchTimes = MeasureTime.measure(TRANSACTION_RUNS, new MeasureRun() {
+                @Override
+                public void run(int i) {
+                    operations.clear();
+                    for (int j = 0; j < TRANSACTION_SIZE && cursor.moveToNext(); ++j) {
+                        Uri channelUri = TvContract.buildChannelUri(cursor.getLong(0));
+                        String number = Integer.toString(i * TRANSACTION_SIZE + j);
+                        operations.add(
+                                ContentProviderOperation.newUpdate(channelUri)
+                                .withValue(Channels.COLUMN_DISPLAY_NUMBER, number)
+                                .build());
+                    }
+                    try {
+                        mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
+                    } catch (OperationApplicationException | RemoteException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            });
+        }
+        report.addValues("Elapsed time for update: ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[1] = Stat.getAverage(applyBatchTimes);
+
+        // Query channels
+        applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
+            @Override
+            public void run(int i) {
+                try (Cursor cursor = mContentResolver.query(Channels.CONTENT_URI, null, null,
+                        null, null)) {
+                    while (cursor.moveToNext()) {
+                        // Do nothing. Just iterate all the items.
+                    }
+                }
+            }
+        });
+        report.addValues("Elapsed time for query (channels): ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[2] = Stat.getAverage(applyBatchTimes);
+
+        // Query a channel
+        try (final Cursor cursor = mContentResolver.query(Channels.CONTENT_URI,
+                projection, null, null, null)) {
+            applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
+                @Override
+                public void run(int i) {
+                    assertTrue(cursor.moveToNext());
+                    try (Cursor c = mContentResolver.query(TvContract.buildChannelUri(
+                            cursor.getLong(0)), null, null, null, null)) {
+                        while (c.moveToNext()) {
+                            // Do nothing. Just iterate all the items.
+                        }
+                    }
+                }
+            });
+        }
+        report.addValues("Elapsed time for query (a channel): ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[3] = Stat.getAverage(applyBatchTimes);
+
+        // Delete
+        applyBatchTimes = MeasureTime.measure(1, new MeasureRun() {
+            @Override
+            public void run(int i) {
+                mContentResolver.delete(TvContract.buildChannelsUriForInput(mInputId), null, null);
+            }
+        });
+        report.addValues("Elapsed time for delete: ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[4] = Stat.getAverage(applyBatchTimes);
+
+        report.addValues("Average elapsed time for insert, update, query (channels), "
+                + "query (a channel), delete: ",
+                averages, ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.submit(getInstrumentation());
+    }
+
+    @TimeoutReq(minutes = 12)
+    public void testPrograms() throws Exception {
+        if (!mHasTvInputFramework) return;
+        double[] averages = new double[7];
+
+        // Prepare (insert channels)
+        final ArrayList<ContentProviderOperation> operations = new ArrayList<>();
+        final int TRANSACTION_SIZE = 1000;
+        final int NUM_CHANNELS = 100;
+        final List<Uri> channelUris = new ArrayList<>();
+
+        operations.clear();
+        for (int i = 0; i < NUM_CHANNELS; ++i) {
+            ContentValues values = new ContentValues();
+            values.put(Channels.COLUMN_INPUT_ID, mInputId);
+            values.put(Channels.COLUMN_SERVICE_TYPE,
+                    Channels.SERVICE_TYPE_AUDIO_VIDEO);
+            values.put(Channels.COLUMN_TYPE, Channels.TYPE_OTHER);
+            operations.add(
+                    ContentProviderOperation.newInsert(Channels.CONTENT_URI)
+                    .withValues(values).build());
+        }
+        try {
+            ContentProviderResult[] results =
+                    mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
+            for (ContentProviderResult result : results) {
+                channelUris.add(result.uri);
+            }
+        } catch (OperationApplicationException | RemoteException e) {
+            throw new RuntimeException(e);
+        }
+
+        // Insert
+        double[] applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
+            @Override
+            public void run(int i) {
+                operations.clear();
+                Uri channelUri = channelUris.get(i);
+                long channelId = ContentUris.parseId(channelUri);
+                for (int j = 0; j < TRANSACTION_SIZE; ++j) {
+                    ContentValues values = new ContentValues();
+                    values.put(Programs.COLUMN_CHANNEL_ID, channelId);
+                    operations.add(
+                            ContentProviderOperation.newInsert(Programs.CONTENT_URI)
+                            .withValues(values).build());
+                }
+                try {
+                    mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
+                } catch (OperationApplicationException | RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        });
+        DeviceReportLog report = new DeviceReportLog();
+        report.addValues("Elapsed time for insert: ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[0] = Stat.getAverage(applyBatchTimes);
+
+        // Update
+        final long PROGRAM_DURATION_MS = 60 * 1000;
+        final String[] projection = { Programs._ID };
+        applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
+            @Override
+            public void run(int i) {
+                Uri channelUri = channelUris.get(i);
+                operations.clear();
+                try (Cursor cursor = mContentResolver.query(
+                        TvContract.buildProgramsUriForChannel(channelUri),
+                        projection, null, null, null)) {
+                    long startTimeMs = 0;
+                    long endTimeMs = 0;
+                    while (cursor.moveToNext()) {
+                        Uri programUri = TvContract.buildProgramUri(cursor.getLong(0));
+                        endTimeMs += PROGRAM_DURATION_MS;
+                        operations.add(
+                                ContentProviderOperation.newUpdate(programUri)
+                                .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS, startTimeMs)
+                                .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS, endTimeMs)
+                                .build());
+                        startTimeMs = endTimeMs;
+                    }
+                }
+                try {
+                    mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
+                } catch (OperationApplicationException | RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        });
+        report.addValues("Elapsed time for update: ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[1] = Stat.getAverage(applyBatchTimes);
+
+        // Query programs
+        applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
+            @Override
+            public void run(int i) {
+                try (Cursor cursor = mContentResolver.query(Programs.CONTENT_URI, null, null,
+                        null, null)) {
+                    while (cursor.moveToNext()) {
+                        // Do nothing. Just iterate all the items.
+                    }
+                }
+            }
+        });
+        report.addValues("Elapsed time for query (programs): ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[2] = Stat.getAverage(applyBatchTimes);
+
+        // Query programs with selection
+        applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
+            @Override
+            public void run(int i) {
+                Uri channelUri = channelUris.get(i);
+                try (Cursor cursor = mContentResolver.query(
+                        TvContract.buildProgramsUriForChannel(
+                                channelUri, 0,
+                                PROGRAM_DURATION_MS * TRANSACTION_SIZE / 2),
+                        null, null, null, null)) {
+                    while (cursor.moveToNext()) {
+                        // Do nothing. Just iterate all the items.
+                    }
+                }
+            }
+        });
+        report.addValues("Elapsed time for query (programs with selection): ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[3] = Stat.getAverage(applyBatchTimes);
+
+        // Query a program
+        try (final Cursor cursor = mContentResolver.query(Programs.CONTENT_URI,
+                projection, null, null, null)) {
+            applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
+                @Override
+                public void run(int i) {
+                    assertTrue(cursor.moveToNext());
+                    try (Cursor c = mContentResolver.query(TvContract.buildProgramUri(
+                            cursor.getLong(0)), null, null, null, null)) {
+                        while (c.moveToNext()) {
+                            // Do nothing. Just iterate all the items.
+                        }
+                    }
+                }
+            });
+        }
+        report.addValues("Elapsed time for query (a program): ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[4] = Stat.getAverage(applyBatchTimes);
+
+        // Delete programs
+        applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
+            @Override
+            public void run(int i) {
+                Uri channelUri = channelUris.get(i);
+                mContentResolver.delete(
+                        TvContract.buildProgramsUriForChannel(
+                                channelUri,
+                                PROGRAM_DURATION_MS * TRANSACTION_SIZE / 2,
+                                PROGRAM_DURATION_MS * TRANSACTION_SIZE),
+                        null, null);
+            }
+        });
+        report.addValues("Elapsed time for delete programs: ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[5] = Stat.getAverage(applyBatchTimes);
+
+        // Delete channels
+        applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
+            @Override
+            public void run(int i) {
+                Uri channelUri = channelUris.get(i);
+                mContentResolver.delete(channelUri, null, null);
+            }
+        });
+        report.addValues("Elapsed time for delete channels: ",
+                applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
+        averages[6] = Stat.getAverage(applyBatchTimes);
+
+        report.addValues("Average elapsed time for insert, update, query (programs), "
+                + "query (programs with selection), query (a channel), delete (channels), "
+                + "delete (programs): ",
+                averages, ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.submit(getInstrumentation());
+    }
+}
diff --git a/tests/ui/Android.mk b/tests/ui/Android.mk
new file mode 100644
index 0000000..e77f035
--- /dev/null
+++ b/tests/ui/Android.mk
@@ -0,0 +1,36 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsUiDeviceTestCases
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := 16
+
+include $(BUILD_CTS_PACKAGE)
+
+
diff --git a/tests/ui/AndroidManifest.xml b/tests/ui/AndroidManifest.xml
new file mode 100644
index 0000000..5ed06b4
--- /dev/null
+++ b/tests/ui/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.ui.cts" >
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <activity
+            android:name=".ScrollingActivity"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:label="UI Latency measurement"
+        android:targetPackage="android.ui.cts" >
+        <meta-data
+            android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/ui/AndroidTest.xml b/tests/ui/AndroidTest.xml
new file mode 100644
index 0000000..de75d28
--- /dev/null
+++ b/tests/ui/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS UI test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsUiDeviceTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.ui.cts" />
+        <option name="runtime-hint" value="5m" />
+    </test>
+</configuration>
diff --git a/tests/ui/src/android/ui/cts/ScrollingActivity.java b/tests/ui/src/android/ui/cts/ScrollingActivity.java
new file mode 100644
index 0000000..d5fc4b0
--- /dev/null
+++ b/tests/ui/src/android/ui/cts/ScrollingActivity.java
@@ -0,0 +1,99 @@
+/*
+ * 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 android.ui.cts;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Activity for measuring scrolling time of long list.
+ */
+public class ScrollingActivity extends ListActivity implements OnScrollListener {
+    static final String TAG = "ScrollingActivity";
+    private static final String NUM_ELEMENTS_EXTRA = "num_elements";
+    private static final int NUM_ELEMENTS_DEFAULT = 10000;
+    private static final int SCROLL_TIME_IN_MS = 1;
+    private static final int WAIT_TIMEOUT_IN_SECS = 5 * 60;
+    private String[] mItems;
+    private CountDownLatch mLatchStop = null;
+    private int mTargetLoc;
+    private int mNumElements;
+
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        mNumElements = getIntent().getIntExtra(NUM_ELEMENTS_EXTRA, NUM_ELEMENTS_DEFAULT);
+        mItems = new String[mNumElements];
+        for (int i = 0; i < mNumElements; i++) {
+            mItems[i] = Integer.toString(i);
+        }
+        setListAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, mItems));
+        ListView view = getListView();
+        view.setOnScrollListener(this);
+    }
+
+    public boolean scrollToTop() {
+        return doScroll(0);
+    }
+    public boolean scrollToBottom() {
+        return doScroll(mNumElements - 1);
+    }
+
+    private boolean doScroll(final int loc) {
+        mLatchStop = new CountDownLatch(1);
+        mTargetLoc = loc;
+        final ListView view = getListView();
+        runOnUiThread( new Runnable() {
+            @Override
+            public void run() {
+                view.smoothScrollToPositionFromTop(loc, 0, SCROLL_TIME_IN_MS);
+            }
+        });
+        boolean result = false;
+        try {
+            result = mLatchStop.await(WAIT_TIMEOUT_IN_SECS, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        mLatchStop = null;
+        return result;
+    }
+
+    @Override
+    public void onScrollStateChanged(AbsListView view, int scrollState) {
+
+    }
+
+    @Override
+    public void onScroll(AbsListView view, int firstVisibleItem,
+            int visibleItemCount, int totalItemCount) {
+        //Log.i(TAG, "onScroll " + firstVisibleItem + " " + visibleItemCount);
+        if ((mTargetLoc >= firstVisibleItem) &&
+                (mTargetLoc <= (firstVisibleItem + visibleItemCount))) {
+            if (mLatchStop != null) {
+                mLatchStop.countDown();
+            }
+        }
+    }
+}
diff --git a/tests/ui/src/android/ui/cts/ScrollingTest.java b/tests/ui/src/android/ui/cts/ScrollingTest.java
new file mode 100644
index 0000000..4902807
--- /dev/null
+++ b/tests/ui/src/android/ui/cts/ScrollingTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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 android.ui.cts;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.MeasureRun;
+import com.android.compatibility.common.util.MeasureTime;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+import com.android.cts.util.TimeoutReq;
+
+import java.io.IOException;
+
+public class ScrollingTest extends ActivityInstrumentationTestCase2<ScrollingActivity> {
+    private ScrollingActivity mActivity;
+
+    public ScrollingTest() {
+        super(ScrollingActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        getInstrumentation().waitForIdleSync();
+        try {
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                }
+            });
+        } catch (Throwable e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mActivity = null;
+        super.tearDown();
+    }
+
+    @TimeoutReq(minutes = 30)
+    public void testFullScrolling() throws Exception {
+        final int NUMBER_REPEAT = 10;
+        final ScrollingActivity activity = mActivity;
+        double[] results = MeasureTime.measure(NUMBER_REPEAT, new MeasureRun() {
+
+            @Override
+            public void run(int i) throws IOException {
+                assertTrue(activity.scrollToBottom());
+                assertTrue(activity.scrollToTop());
+            }
+        });
+        DeviceReportLog report = new DeviceReportLog();
+        report.addValues("scrolling time", results, ResultType.LOWER_BETTER,ResultUnit.MS);
+        Stat.StatResult stat = Stat.getStat(results);
+        report.setSummary("scrolling time", stat.mAverage, ResultType.LOWER_BETTER,ResultUnit.MS);
+        report.submit(getInstrumentation());
+    }
+}
diff --git a/tests/uiautomator/Android.mk b/tests/uiautomator/Android.mk
index d0d4b8e..a3094f9 100644
--- a/tests/uiautomator/Android.mk
+++ b/tests/uiautomator/Android.mk
@@ -21,12 +21,15 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_MODULE := CtsUiAutomatorTests
-LOCAL_JAVA_LIBRARIES := uiautomator.core
+LOCAL_MODULE := CtsUiAutomatorTestCases
+LOCAL_STATIC_JAVA_LIBRARIES := uiautomator.core
 LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_CTS_TEST_APK := CtsUiAutomatorApp
-LOCAL_CTS_TEST_APP_PACKAGE := com.android.cts.uiautomator
-LOCAL_CTS_TEST_PACKAGE := android.uiautomator
+LOCAL_CTS_TEST_APK := CtsUiAutomatorTestApp
+LOCAL_CTS_TEST_APP_PACKAGE := com.android.uiautomator.app
+LOCAL_CTS_TEST_PACKAGE := com.android.uiautomator.cts
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
 include $(BUILD_CTS_UI_JAVA_LIBRARY)
 
diff --git a/tests/uiautomator/AndroidTest.xml b/tests/uiautomator/AndroidTest.xml
new file mode 100644
index 0000000..c931f59
--- /dev/null
+++ b/tests/uiautomator/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS UI Automator test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsUiAutomatorTestApp.apk" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsUiAutomatorTestCases.jar->/data/local/tmp/CtsUiAutomatorTestCases.jar" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.UiAutomatorTest" >
+        <option name="jar-path" value="CtsUiAutomatorTestCases.jar" />
+        <option name="capture-logs" value="OFF" />
+    </test>
+</configuration>
diff --git a/tests/uiautomator/app/Android.mk b/tests/uiautomator/app/Android.mk
new file mode 100644
index 0000000..0bde598
--- /dev/null
+++ b/tests/uiautomator/app/Android.mk
@@ -0,0 +1,36 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := CtsUiAutomatorTestApp
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/uiautomator/app/AndroidManifest.xml b/tests/uiautomator/app/AndroidManifest.xml
new file mode 100644
index 0000000..25f746b
--- /dev/null
+++ b/tests/uiautomator/app/AndroidManifest.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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.uiautomator.app"
+    android:versionCode="1"
+    android:versionName="1.0" >
+    <uses-sdk
+        android:minSdkVersion="14"
+        android:targetSdkVersion="15" />
+
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/title_test_list" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".SinglePaneDetailActivity"
+            android:label="@string/title_test_detail" >
+            <meta-data
+                android:name="android.support.PARENT_ACTIVITY"
+                android:value="FragmentActivity" />
+        </activity>
+     </application>
+
+</manifest>
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-hdpi/ic_action_search.png b/tests/uiautomator/app/res/drawable-hdpi/ic_action_search.png
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-hdpi/ic_action_search.png
rename to tests/uiautomator/app/res/drawable-hdpi/ic_action_search.png
Binary files differ
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-hdpi/ic_launcher.png b/tests/uiautomator/app/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-hdpi/ic_launcher.png
rename to tests/uiautomator/app/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-ldpi/ic_launcher.png b/tests/uiautomator/app/res/drawable-ldpi/ic_launcher.png
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-ldpi/ic_launcher.png
rename to tests/uiautomator/app/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-mdpi/ic_action_search.png b/tests/uiautomator/app/res/drawable-mdpi/ic_action_search.png
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-mdpi/ic_action_search.png
rename to tests/uiautomator/app/res/drawable-mdpi/ic_action_search.png
Binary files differ
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-mdpi/ic_launcher.png b/tests/uiautomator/app/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-mdpi/ic_launcher.png
rename to tests/uiautomator/app/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-xhdpi/ic_action_search.png b/tests/uiautomator/app/res/drawable-xhdpi/ic_action_search.png
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-xhdpi/ic_action_search.png
rename to tests/uiautomator/app/res/drawable-xhdpi/ic_action_search.png
Binary files differ
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-xhdpi/ic_launcher.png b/tests/uiautomator/app/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/drawable-xhdpi/ic_launcher.png
rename to tests/uiautomator/app/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout-land/test5_detail_fragment.xml b/tests/uiautomator/app/res/layout-land/test5_detail_fragment.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout-land/test5_detail_fragment.xml
rename to tests/uiautomator/app/res/layout-land/test5_detail_fragment.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/activity_main.xml b/tests/uiautomator/app/res/layout/activity_main.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/activity_main.xml
rename to tests/uiautomator/app/res/layout/activity_main.xml
diff --git a/tests/uiautomator/app/res/layout/list_activity.xml b/tests/uiautomator/app/res/layout/list_activity.xml
new file mode 100644
index 0000000..faedc91
--- /dev/null
+++ b/tests/uiautomator/app/res/layout/list_activity.xml
@@ -0,0 +1,26 @@
+<?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.
+ -->
+<fragment xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:name="com.android.uiautomator.app.TestListFragment"
+    android:id="@+id/item_list"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginLeft="16dp"
+    android:layout_marginRight="16dp"
+    tools:context=".MainActivity" />
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/simple_list_item_selected.xml b/tests/uiautomator/app/res/layout/simple_list_item_selected.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/simple_list_item_selected.xml
rename to tests/uiautomator/app/res/layout/simple_list_item_selected.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/singlepane_activity.xml b/tests/uiautomator/app/res/layout/singlepane_activity.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/singlepane_activity.xml
rename to tests/uiautomator/app/res/layout/singlepane_activity.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test1_detail_fragment.xml b/tests/uiautomator/app/res/layout/test1_detail_fragment.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test1_detail_fragment.xml
rename to tests/uiautomator/app/res/layout/test1_detail_fragment.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test2_detail_fragment.xml b/tests/uiautomator/app/res/layout/test2_detail_fragment.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test2_detail_fragment.xml
rename to tests/uiautomator/app/res/layout/test2_detail_fragment.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test3_detail_fragment.xml b/tests/uiautomator/app/res/layout/test3_detail_fragment.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test3_detail_fragment.xml
rename to tests/uiautomator/app/res/layout/test3_detail_fragment.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test4_detail_fragment.xml b/tests/uiautomator/app/res/layout/test4_detail_fragment.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test4_detail_fragment.xml
rename to tests/uiautomator/app/res/layout/test4_detail_fragment.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test5_detail_fragment.xml b/tests/uiautomator/app/res/layout/test5_detail_fragment.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test5_detail_fragment.xml
rename to tests/uiautomator/app/res/layout/test5_detail_fragment.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test6_detail_fragment.xml b/tests/uiautomator/app/res/layout/test6_detail_fragment.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test6_detail_fragment.xml
rename to tests/uiautomator/app/res/layout/test6_detail_fragment.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test_results_detail_fragment.xml b/tests/uiautomator/app/res/layout/test_results_detail_fragment.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/test_results_detail_fragment.xml
rename to tests/uiautomator/app/res/layout/test_results_detail_fragment.xml
diff --git a/tests/uiautomator/app/res/layout/twopane_activity.xml b/tests/uiautomator/app/res/layout/twopane_activity.xml
new file mode 100644
index 0000000..a787368
--- /dev/null
+++ b/tests/uiautomator/app/res/layout/twopane_activity.xml
@@ -0,0 +1,41 @@
+<?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"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginLeft="16dp"
+    android:layout_marginRight="16dp"
+    android:divider="?android:attr/dividerHorizontal"
+    android:showDividers="middle"
+    tools:context=".TestListActivity">
+
+    <fragment
+        android:id="@+id/item_list"
+        android:name="com.android.uiautomator.app.TestListFragment"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1" />
+
+    <FrameLayout android:id="@+id/test_detail_container"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="3" />
+
+</LinearLayout>
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/activity_main.xml b/tests/uiautomator/app/res/menu/activity_main.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/activity_main.xml
rename to tests/uiautomator/app/res/menu/activity_main.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test1_detail_activity.xml b/tests/uiautomator/app/res/menu/test1_detail_activity.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test1_detail_activity.xml
rename to tests/uiautomator/app/res/menu/test1_detail_activity.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test2_detail_activity.xml b/tests/uiautomator/app/res/menu/test2_detail_activity.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test2_detail_activity.xml
rename to tests/uiautomator/app/res/menu/test2_detail_activity.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test3_detail_activity.xml b/tests/uiautomator/app/res/menu/test3_detail_activity.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test3_detail_activity.xml
rename to tests/uiautomator/app/res/menu/test3_detail_activity.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test4_detail_activity.xml b/tests/uiautomator/app/res/menu/test4_detail_activity.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test4_detail_activity.xml
rename to tests/uiautomator/app/res/menu/test4_detail_activity.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test5_detail_activity.xml b/tests/uiautomator/app/res/menu/test5_detail_activity.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test5_detail_activity.xml
rename to tests/uiautomator/app/res/menu/test5_detail_activity.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test6_detail_activity.xml b/tests/uiautomator/app/res/menu/test6_detail_activity.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test6_detail_activity.xml
rename to tests/uiautomator/app/res/menu/test6_detail_activity.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test_results_detail_activity.xml b/tests/uiautomator/app/res/menu/test_results_detail_activity.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/menu/test_results_detail_activity.xml
rename to tests/uiautomator/app/res/menu/test_results_detail_activity.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-large/dimens.xml b/tests/uiautomator/app/res/values-large/dimens.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-large/dimens.xml
rename to tests/uiautomator/app/res/values-large/dimens.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-large/refs.xml b/tests/uiautomator/app/res/values-large/refs.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-large/refs.xml
rename to tests/uiautomator/app/res/values-large/refs.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-sw600dp/refs.xml b/tests/uiautomator/app/res/values-sw600dp/refs.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-sw600dp/refs.xml
rename to tests/uiautomator/app/res/values-sw600dp/refs.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-v11/styles.xml b/tests/uiautomator/app/res/values-v11/styles.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-v11/styles.xml
rename to tests/uiautomator/app/res/values-v11/styles.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-v14/styles.xml b/tests/uiautomator/app/res/values-v14/styles.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-v14/styles.xml
rename to tests/uiautomator/app/res/values-v14/styles.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-watch/styles.xml b/tests/uiautomator/app/res/values-watch/styles.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values-watch/styles.xml
rename to tests/uiautomator/app/res/values-watch/styles.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values/dimens.xml b/tests/uiautomator/app/res/values/dimens.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values/dimens.xml
rename to tests/uiautomator/app/res/values/dimens.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values/strings.xml b/tests/uiautomator/app/res/values/strings.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values/strings.xml
rename to tests/uiautomator/app/res/values/strings.xml
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values/styles.xml b/tests/uiautomator/app/res/values/styles.xml
similarity index 100%
rename from tests/uiautomator/test-apps/CtsUiAutomatorApp/res/values/styles.xml
rename to tests/uiautomator/app/res/values/styles.xml
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/MainActivity.java b/tests/uiautomator/app/src/com/android/uiautomator/app/MainActivity.java
new file mode 100644
index 0000000..feb6767
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/MainActivity.java
@@ -0,0 +1,59 @@
+/*
+ * 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.uiautomator.app;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.view.WindowManager;
+
+public class MainActivity extends FragmentActivity implements TestListFragment.Callbacks {
+
+    private boolean mTwoPane;
+    public static final String LOG_TAG = "UiAutomatorApp";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // If the device is locked, this attempts to dismiss the KeyGuard
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
+                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
+                      WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+        setContentView(R.layout.list_activity);
+
+        if (findViewById(R.id.test_detail_container) != null) {
+            mTwoPane = true;
+            ((TestListFragment) getSupportFragmentManager().findFragmentById(R.id.item_list))
+                    .setActivateOnItemClick(true);
+        }
+    }
+
+    @Override
+    public void onItemSelected(String id) {
+        if (mTwoPane) {
+            Fragment fragment = TestItems.getFragment(id);
+            getSupportFragmentManager().beginTransaction()
+                    .replace(R.id.test_detail_container, fragment).commit();
+        } else {
+            Intent detailIntent = new Intent(this, SinglePaneDetailActivity.class);
+            detailIntent.putExtra("item_id", id);
+            startActivity(detailIntent);
+        }
+    }
+}
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/SinglePaneDetailActivity.java b/tests/uiautomator/app/src/com/android/uiautomator/app/SinglePaneDetailActivity.java
new file mode 100644
index 0000000..553557e
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/SinglePaneDetailActivity.java
@@ -0,0 +1,56 @@
+/*
+ * 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.uiautomator.app;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.NavUtils;
+import android.view.Menu;
+import android.view.MenuItem;
+
+public class SinglePaneDetailActivity extends FragmentActivity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.singlepane_activity);
+        getActionBar().setDisplayHomeAsUpEnabled(true);
+
+        if (savedInstanceState == null) {
+            Fragment fragment = TestItems.getFragment(getIntent().getStringExtra("item_id"));
+            getSupportFragmentManager().beginTransaction()
+                    .add(R.id.test_results_detail_container, fragment).commit();
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.test_results_detail_activity, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                NavUtils.navigateUpFromSameTask(this);
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+}
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/Test1DetailFragment.java b/tests/uiautomator/app/src/com/android/uiautomator/app/Test1DetailFragment.java
new file mode 100644
index 0000000..f7dccb3
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/Test1DetailFragment.java
@@ -0,0 +1,80 @@
+/*
+ * 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.uiautomator.app;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+
+public class Test1DetailFragment extends Fragment {
+
+    public static final String ARG_ITEM_ID = "item_id";
+    private Button mSubmitButton;
+    private EditText mEditText;
+    TestItems.TestItem mItem;
+
+    public Test1DetailFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (getArguments().containsKey(ARG_ITEM_ID)) {
+            mItem = TestItems.getTest(getArguments().getString(ARG_ITEM_ID));
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+        View rootView = inflater.inflate(R.layout.test1_detail_fragment, container, false);
+        if (mItem != null) {
+            ((EditText) rootView.findViewById(R.id.test1TextField)).setText(mItem.mName);
+
+            mSubmitButton = (Button) rootView.findViewById(R.id.test1SubmitButton);
+            mEditText = (EditText) rootView.findViewById(R.id.test1TextField);
+            mEditText.setText("");
+            mSubmitButton.setOnClickListener(new Button.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    final String savedInput = mEditText.getText().toString();
+                    // clear so we won't be confused by the input text in
+                    // validation
+                    mEditText.setText("");
+                    // close soft keyboard
+                    InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
+                            Context.INPUT_METHOD_SERVICE);
+                    imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
+                    // display the submitted text
+                    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+                    builder.setTitle(R.string.item1_dialog_title);
+                    builder.setPositiveButton(R.string.OK, null);
+                    builder.setMessage(savedInput);
+                    AlertDialog diag = builder.create();
+                    diag.show();
+                }
+            });
+        }
+        return rootView;
+    }
+}
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/Test2DetailFragment.java b/tests/uiautomator/app/src/com/android/uiautomator/app/Test2DetailFragment.java
new file mode 100644
index 0000000..1cb3a69
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/Test2DetailFragment.java
@@ -0,0 +1,153 @@
+/*
+ * 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.uiautomator.app;
+
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+public class Test2DetailFragment extends Fragment {
+    public static final String ARG_ITEM_ID = "item_id";
+    private Button mButton1, mButton2, mButton3, mDynaButton;
+
+    public Test2DetailFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        inflater.inflate(R.menu.test2_detail_activity, menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        builder.setTitle(R.string.dialog_title_result);
+        builder.setMessage(item.getTitle());
+        builder.setPositiveButton(R.string.OK, null);
+        AlertDialog diag = builder.create();
+        diag.show();
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+        View rootView = inflater.inflate(R.layout.test2_detail_fragment, container, false);
+
+        mButton1 = (Button) rootView.findViewById(R.id.test2button1);
+        mButton2 = (Button) rootView.findViewById(R.id.test2button2);
+        mButton3 = (Button) rootView.findViewById(R.id.test2button3);
+        mDynaButton = (Button) rootView.findViewById(R.id.test2dynaButton);
+
+        mButton1.setOnClickListener(new Button.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+                builder.setTitle(R.string.dialog_title_result);
+                builder.setPositiveButton(R.string.OK, null);
+                builder.setMessage(R.string.button1);
+                AlertDialog diag = builder.create();
+                diag.show();
+            }
+        });
+
+        mButton1.setOnLongClickListener(new Button.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+                builder.setTitle(R.string.dialog_title_result);
+                builder.setPositiveButton(R.string.OK, null);
+                builder.setMessage(R.string.button1long);
+                AlertDialog diag = builder.create();
+                diag.show();
+                return true;
+            }
+        });
+
+        mButton2.setOnClickListener(new Button.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+                builder.setTitle(R.string.dialog_title_result);
+                builder.setPositiveButton(R.string.OK, null);
+                builder.setMessage(R.string.button2);
+                AlertDialog diag = builder.create();
+                diag.show();
+            }
+        });
+
+        mButton2.setOnLongClickListener(new Button.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+                builder.setTitle(R.string.dialog_title_result);
+                builder.setPositiveButton(R.string.OK, null);
+                builder.setMessage(R.string.button2long);
+                AlertDialog diag = builder.create();
+                diag.show();
+                return true;
+            }
+        });
+
+        mButton3.setOnClickListener(new Button.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+                builder.setTitle(R.string.dialog_title_result);
+                builder.setPositiveButton(R.string.OK, null);
+                builder.setMessage(R.string.button3);
+                AlertDialog diag = builder.create();
+                diag.show();
+            }
+        });
+
+        mButton3.setOnLongClickListener(new Button.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+                builder.setTitle(R.string.dialog_title_result);
+                builder.setPositiveButton(R.string.OK, null);
+                builder.setMessage(R.string.button3long);
+                AlertDialog diag = builder.create();
+                diag.show();
+                return true;
+            }
+        });
+
+        mDynaButton.setOnClickListener(new Button.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mDynaButton.setText(R.string.buttonAfter);
+                mDynaButton.setContentDescription(getString(R.string.buttonAfter));
+            }
+        });
+
+        return rootView;
+    }
+}
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/Test3DetailFragment.java b/tests/uiautomator/app/src/com/android/uiautomator/app/Test3DetailFragment.java
new file mode 100644
index 0000000..cc76401
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/Test3DetailFragment.java
@@ -0,0 +1,134 @@
+/*
+ * 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.uiautomator.app;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+public class Test3DetailFragment extends Fragment {
+
+    public static final String ARG_ITEM_ID = "item_id";
+    private TextView mTextClock;
+    private Button mSubmitButton;
+    private EditText mEditText;
+    private long mCurrentTime;
+    private final Object sync = new Object();
+    private boolean mRunCounter = true;
+
+    public Test3DetailFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        inflater.inflate(R.menu.test2_detail_activity, menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        builder.setTitle(R.string.dialog_title_result);
+        builder.setMessage(item.getTitle());
+        builder.setPositiveButton(R.string.OK, null);
+        AlertDialog diag = builder.create();
+        diag.show();
+        return super.onOptionsItemSelected(item);
+    }
+
+    private final Handler mHandler = new Handler();
+
+    final Runnable mClockRunnable = new Runnable() {
+        @Override
+        public void run() {
+            // call the activity method that updates the UI
+            updateClockOnUi();
+        }
+    };
+
+    private void updateClockOnUi() {
+        synchronized (sync) {
+            mTextClock.setText("" + mCurrentTime);
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+        View rootView = inflater.inflate(R.layout.test3_detail_fragment, container, false);
+        mTextClock = (TextView) rootView.findViewById(R.id.test3ClockTextView);
+        mSubmitButton = (Button) rootView.findViewById(R.id.test3SubmitButton);
+        mEditText = (EditText) rootView.findViewById(R.id.test3TextField);
+        mSubmitButton.setOnClickListener(new Button.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // close soft keyboard
+                InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
+                        Context.INPUT_METHOD_SERVICE);
+                imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
+
+                // display the submitted text
+                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+                builder.setTitle(R.string.test3_dialog_title);
+                builder.setPositiveButton(R.string.OK, null);
+                CharSequence inputText = mEditText.getText();
+                if (inputText != null && !inputText.toString().isEmpty()) {
+                    long inputTime = Long.parseLong(inputText.toString());
+                    builder.setMessage("" + (mCurrentTime - inputTime));
+                } else {
+                    builder.setMessage("<NO DATA>");
+                }
+                AlertDialog diag = builder.create();
+                diag.show();
+                mEditText.setText("");
+                mRunCounter = false;
+            }
+        });
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                while (mRunCounter) {
+                    synchronized (sync) {
+                        mCurrentTime = SystemClock.elapsedRealtime();
+                    }
+                    mHandler.post(mClockRunnable);
+                    SystemClock.sleep(100);
+                }
+            }
+        }).start();
+
+        return rootView;
+    }
+}
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/Test4DetailFragment.java b/tests/uiautomator/app/src/com/android/uiautomator/app/Test4DetailFragment.java
new file mode 100644
index 0000000..cc7b9f8
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/Test4DetailFragment.java
@@ -0,0 +1,178 @@
+/*
+ * 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.uiautomator.app;
+
+import android.app.ActionBar;
+import android.app.FragmentTransaction;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class Test4DetailFragment extends Fragment implements ActionBar.TabListener {
+    public static final String ARG_ITEM_ID = "item_id";
+
+    /**
+     * The {@link android.support.v4.view.PagerAdapter} that will provide
+     * fragments for each of the sections. We use a
+     * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
+     * will keep every loaded fragment in memory. If this becomes too memory
+     * intensive, it may be best to switch to a
+     * {@link android.support.v4.app.FragmentStatePagerAdapter}.
+     */
+    SectionsPagerAdapter mSectionsPagerAdapter;
+
+    /**
+     * The {@link ViewPager} that will host the section contents.
+     */
+    ViewPager mViewPager;
+
+    public Test4DetailFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public void onDestroyView() {
+        getActivity().getActionBar().removeAllTabs();
+        super.onDestroyView();
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+
+        View rootView = inflater.inflate(R.layout.test4_detail_fragment, container, false);
+
+        // Set up the action bar.
+        final ActionBar actionBar = getActivity().getActionBar();
+        if (actionBar.getTabCount() > 0) {
+            return rootView;
+        }
+        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+
+        // Create the adapter that will return a fragment for each of the three
+        // primary sections of the app.
+        mSectionsPagerAdapter = new SectionsPagerAdapter(getActivity().getSupportFragmentManager());
+
+        // Set up the ViewPager with the sections adapter.
+        mViewPager = (ViewPager) rootView.findViewById(R.id.test_4_detail_container);
+        mViewPager.setAdapter(mSectionsPagerAdapter);
+
+        // When swiping between different sections, select the corresponding
+        // tab. We can also use ActionBar.Tab#select() to do this if we have a
+        // reference to the Tab.
+        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+            @Override
+            public void onPageSelected(int position) {
+                actionBar.setSelectedNavigationItem(position);
+            }
+        });
+
+        // For each of the sections in the app, add a tab to the action bar.
+        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
+            // Create a tab with text corresponding to the page title defined by
+            // the adapter. Also specify this Activity object, which implements
+            // the TabListener interface, as the listener for when this tab is
+            // selected.
+            actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i))
+                    .setTabListener(this));
+        }
+        return rootView;
+    }
+
+    @Override
+    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+    }
+
+    @Override
+    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+    }
+
+    @Override
+    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+    }
+
+    /**
+     * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
+     * one of the primary sections of the app.
+     */
+    public class SectionsPagerAdapter extends FragmentPagerAdapter {
+
+        public SectionsPagerAdapter(FragmentManager fm) {
+            super(fm);
+        }
+
+        @Override
+        public Fragment getItem(int i) {
+            Fragment fragment = new DummySectionFragment();
+            Bundle args = new Bundle();
+            args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1);
+            fragment.setArguments(args);
+            return fragment;
+        }
+
+        @Override
+        public int getCount() {
+            return 4;
+        }
+
+        @Override
+        public CharSequence getPageTitle(int position) {
+            switch (position) {
+                case 0:
+                    return getString(R.string.title_section1).toUpperCase();
+                case 1:
+                    return getString(R.string.title_section2).toUpperCase();
+                case 2:
+                    return getString(R.string.title_section3).toUpperCase();
+                case 3:
+                    return getString(R.string.title_section4).toUpperCase();
+            }
+            return null;
+        }
+    }
+
+    /**
+     * A dummy fragment representing a section of the app, but that simply
+     * displays dummy text.
+     */
+    public static class DummySectionFragment extends Fragment {
+        public DummySectionFragment() {
+        }
+
+        public static final String ARG_SECTION_NUMBER = "section_number";
+
+        @Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            TextView textView = new TextView(getActivity());
+            textView.setGravity(Gravity.CENTER);
+            Bundle args = getArguments();
+            textView.setText("[ " + Integer.toString(args.getInt(ARG_SECTION_NUMBER)) + " ]");
+            return textView;
+        }
+    }
+}
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/Test5DetailFragment.java b/tests/uiautomator/app/src/com/android/uiautomator/app/Test5DetailFragment.java
new file mode 100644
index 0000000..0e3eec4
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/Test5DetailFragment.java
@@ -0,0 +1,151 @@
+/*
+ * 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.uiautomator.app;
+
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.ImageButton;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+
+public class Test5DetailFragment extends Fragment {
+
+    public static final String ARG_ITEM_ID = "item_id";
+
+    class PointerEvent {
+        int startX;
+        int startY;
+        int endX;
+        int endY;
+    }
+
+    private final PointerEvent mPointerEvent = new PointerEvent();
+
+    public Test5DetailFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+        View rootView = inflater.inflate(R.layout.test5_detail_fragment, container, false);
+
+        // Set the content description for the following
+        Spinner spinner = (Spinner) rootView.findViewById(R.id.test_5_spinner);
+        spinner.setContentDescription("Spinner");
+        ImageButton imageButton = (ImageButton) rootView.findViewById(R.id.test_5_imageButton);
+        imageButton.setContentDescription("Image button");
+
+        // Each time this view is displayed, reset the following states
+        SeekBar seekBar = (SeekBar) rootView.findViewById(R.id.test_5_seekBar);
+        seekBar.setProgress(50);
+        seekBar.setContentDescription("Progress is 50 %");
+        CheckBox checkbox = (CheckBox) rootView.findViewById(R.id.test_5_checkBox);
+        checkbox.setChecked(false);
+
+        // Register click event handlers for the following
+        Button button = (Button) rootView.findViewById(R.id.test_5_button1);
+        button.setOnClickListener(new Button.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // we want an artificial crash
+                throw new RuntimeException("Artificial crash to test UiWatcher");
+            }
+        });
+
+        imageButton.setOnTouchListener(new ImageButton.OnTouchListener() {
+
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                    resetTouchResults();
+                    collectStartAction(event, v);
+                } else if (event.getAction() == MotionEvent.ACTION_UP) {
+                    collectEndAction(event, v);
+                    displayTouchResults();
+                }
+                return false;
+            }
+        });
+
+        return rootView;
+    }
+
+    private void displayTouchResults() {
+        StringBuilder output = new StringBuilder();
+
+        output.append(String.format("%d,%d:%d,%d\n",
+                mPointerEvent.startX, mPointerEvent.startY, mPointerEvent.endX,
+                mPointerEvent.endY));
+
+        // display the submitted text
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        builder.setTitle(R.string.drag_item_touch_dialog_title);
+        builder.setPositiveButton(R.string.OK, null);
+        builder.setMessage(output.toString());
+        AlertDialog diag = builder.create();
+        diag.show();
+    }
+
+    /**
+     * Clears all collected pointer results
+     */
+    private void resetTouchResults() {
+         mPointerEvent.startX = mPointerEvent.startY =
+                    mPointerEvent.endX = mPointerEvent.endY = -1;
+    }
+
+    /**
+     * Collects pointer touch information converting from relative to absolute before
+     * storing it as starting touch coordinates.
+     *
+     * @param event
+     * @param view
+     * @param pointerIndex
+     */
+    private void collectStartAction(MotionEvent event, View view) {
+        int offsetInScreen[] = new int[2];
+        view.getLocationOnScreen(offsetInScreen);
+        mPointerEvent.startX = (int)(event.getX() + offsetInScreen[0]);
+        mPointerEvent.startY = (int)(event.getY() + offsetInScreen[1]);
+    }
+
+    /**
+     * Collects pointer touch information converting from relative to absolute before
+     * storing it as ending touch coordinates.
+     *
+     * @param event
+     * @param view
+     * @param pointerIndex
+     */
+    private void collectEndAction(MotionEvent event, View view) {
+        int offsetInScreen[] = new int[2];
+        view.getLocationOnScreen(offsetInScreen);
+        mPointerEvent.endX = (int)(event.getX() + offsetInScreen[0]);
+        mPointerEvent.endY = (int)(event.getY() + offsetInScreen[1]);
+    }
+}
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/Test6DetailFragment.java b/tests/uiautomator/app/src/com/android/uiautomator/app/Test6DetailFragment.java
new file mode 100644
index 0000000..d1149a6
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/Test6DetailFragment.java
@@ -0,0 +1,50 @@
+/*
+ * 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.uiautomator.app;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+
+public class Test6DetailFragment extends Fragment {
+    public static final String ARG_ITEM_ID = "item_id";
+    private final static String PAGE = "<html><body>"
+            + "This is test <b>6</b> for WebView text traversal test."
+            + "<p/><a href=\"http://google.com\">This is a link to google</a><br/>"
+            + "<h5>This is h5 text</h5>"
+            + "<a href=\"http://yahoo.com\">This is a link to yahoo</a>"
+            + "<p/><h4>This is h4 text</h4>" + "</body></html>";
+
+    public Test6DetailFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+        View rootView = inflater.inflate(R.layout.test6_detail_fragment, container, false);
+        WebView wv = (WebView) rootView.findViewById(R.id.test6WebView);
+        wv.loadData(PAGE, "text/html", null);
+        return rootView;
+    }
+}
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/TestGenericDetailFragment.java b/tests/uiautomator/app/src/com/android/uiautomator/app/TestGenericDetailFragment.java
new file mode 100644
index 0000000..d87a849
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/TestGenericDetailFragment.java
@@ -0,0 +1,176 @@
+/*
+ * 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.uiautomator.app;
+
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class TestGenericDetailFragment extends Fragment {
+    public static final String ARG_ITEM_ID = "item_id";
+    TestItems.TestItem mItem;
+
+    private class PointerEvent {
+        int startX;
+        int startY;
+        int endX;
+        int endY;
+    }
+
+    private final PointerEvent[] mPointerEvents = new PointerEvent[10];
+
+    public TestGenericDetailFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (getArguments().containsKey(ARG_ITEM_ID)) {
+            mItem = TestItems.getTest(getArguments().getString(ARG_ITEM_ID));
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+        View rootView = inflater.inflate(R.layout.test_results_detail_fragment, container, false);
+        if (mItem != null) {
+            ((TextView) rootView.findViewById(R.id.testResultsTextView)).setText(mItem.mName);
+        }
+
+        // listen to touch events to verify the multiPointerGesture APIs
+        // Since API Level 18
+        rootView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+
+                switch(event.getAction() & MotionEvent.ACTION_MASK) {
+                    case MotionEvent.ACTION_DOWN:
+                        // Reset any collected touch coordinate results on the primary touch down
+                        resetTouchResults();
+                        // collect this event
+                        collectStartAction(event, v, 0);
+                        break;
+
+                    case MotionEvent.ACTION_POINTER_DOWN:
+                        // collect this event
+                        collectStartAction(event, v, getPointerIndex(event));
+                        break;
+
+                    case MotionEvent.ACTION_POINTER_UP:
+                        // collect this event
+                        collectEndAction(event, v, getPointerIndex(event));
+                        break;
+
+                    case MotionEvent.ACTION_UP:
+                        // collect this event
+                        collectEndAction(event, v, 0);
+                        // on the primary touch up display results collected for all pointers
+                        displayTouchResults();
+                        break;
+                }
+                return true;
+            }
+        });
+
+        return rootView;
+    }
+
+    /**
+     * Displays collected results from all pointers into a dialog view in the following
+     * format: "startX,startY:endX,endY" where each line represent data for a pointer if
+     * multiple pointers (fingers) were detected.
+     */
+    private void displayTouchResults() {
+        StringBuilder output = new StringBuilder();
+        for (int x = 0; x < mPointerEvents.length; x++) {
+            if (mPointerEvents[x].startX == -1)
+                break;
+
+            output.append(String.format("%d,%d:%d,%d\n",
+                    mPointerEvents[x].startX, mPointerEvents[x].startY, mPointerEvents[x].endX,
+                    mPointerEvents[x].endY));
+        }
+
+        // display the submitted text
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        builder.setTitle(R.string.generic_item_touch_dialog_title);
+        builder.setPositiveButton(R.string.OK, null);
+        builder.setMessage(output.toString());
+        AlertDialog diag = builder.create();
+        diag.show();
+    }
+
+    /**
+     * Clears all collected pointer results
+     */
+    private void resetTouchResults() {
+        for (int x = 0; x < mPointerEvents.length; x++) {
+            if (mPointerEvents[x] == null)
+                mPointerEvents[x] = new PointerEvent();
+            mPointerEvents[x].startX = mPointerEvents[x].startY =
+                    mPointerEvents[x].endX = mPointerEvents[x].endY = -1;
+        }
+    }
+
+    /**
+     * Collects pointer touch information converting from relative to absolute before
+     * storing it as starting touch coordinates.
+     *
+     * @param event
+     * @param view
+     * @param pointerIndex
+     */
+    private void collectStartAction(MotionEvent event, View view, int pointerIndex) {
+        int offsetInScreen[] = new int[2];
+        view.getLocationOnScreen(offsetInScreen);
+        mPointerEvents[getPointerId(event)].startX =
+                (int)(event.getX(pointerIndex) + offsetInScreen[0]);
+        mPointerEvents[getPointerId(event)].startY =
+                (int)(event.getY(pointerIndex) + offsetInScreen[1]);
+    }
+
+    /**
+     * Collects pointer touch information converting from relative to absolute before
+     * storing it as ending touch coordinates.
+     *
+     * @param event
+     * @param view
+     * @param pointerIndex
+     */
+    private void collectEndAction(MotionEvent event, View view, int pointerIndex) {
+        int offsetInScreen[] = new int[2];
+        view.getLocationOnScreen(offsetInScreen);
+        mPointerEvents[getPointerId(event)].endX =
+                (int)(event.getX(pointerIndex) + offsetInScreen[0]);
+        mPointerEvents[getPointerId(event)].endY =
+                (int)(event.getY(pointerIndex) + offsetInScreen[1]);
+    }
+
+    private int getPointerId(MotionEvent event) {
+        return event.getPointerId(getPointerIndex(event));
+    }
+
+    private int getPointerIndex(MotionEvent event) {
+        return ((event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
+                >> MotionEvent.ACTION_POINTER_INDEX_SHIFT);
+    }
+}
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/TestItems.java b/tests/uiautomator/app/src/com/android/uiautomator/app/TestItems.java
new file mode 100644
index 0000000..89886fe
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/TestItems.java
@@ -0,0 +1,127 @@
+/*
+ * 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.uiautomator.app;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class TestItems {
+    private static String LOG_TAG = TestItems.class.getSimpleName();
+    private static List<TestItem> ITEMS = new ArrayList<TestItem>();
+    private static Map<String, TestItem> ITEM_MAP = new HashMap<String, TestItem>();
+
+    public static class TestItem {
+        public String mId;
+        public String mName;
+        private final Class<Fragment> mClassFragment;
+        public String mTestDescription;
+
+        @SuppressWarnings("unchecked")
+        public TestItem(String id, String name, Class<?> clsf) {
+            mId = id;
+            mName = name;
+            mClassFragment = (Class<Fragment>) clsf;
+        }
+
+        @Override
+        public String toString() {
+            return mName;
+        }
+    }
+
+    static {
+        addTestItem(new TestItem("1", "Test 1", Test1DetailFragment.class));
+        addTestItem(new TestItem("2", "Test 2", Test2DetailFragment.class));
+        addTestItem(new TestItem("3", "Test 3", Test3DetailFragment.class));
+        addTestItem(new TestItem("4", "Test 4", Test4DetailFragment.class));
+        addTestItem(new TestItem("5", "Test 5", Test5DetailFragment.class));
+        addTestItem(new TestItem("6", "Test 6", Test6DetailFragment.class));
+        addTestItem(new TestItem("7", "Test 7", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("8", "Test 8", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("9", "Test 9", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("10", "Test 10", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("11", "Test 11", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("12", "Test 12", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("13", "Test 13", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("14", "Test 14", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("15", "Test 15", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("16", "Test 16", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("17", "Test 17", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("18", "Test 18", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("19", "Test 19", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("20", "Test 20", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("21", "Test 21", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("22", "Test 22", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("23", "Test 23", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("24", "Test 24", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("25", "Test 25", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("26", "Test 26", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("27", "Test 27", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("28", "Test 28", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("29", "Test 29", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("30", "Test 30", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("31", "Test 31", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("32", "Test 32", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("33", "Test 33", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("34", "Test 34", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("35", "Test 35", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("36", "Test 36", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("37", "Test 37", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("38", "Test 38", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("39", "Test 39", TestGenericDetailFragment.class));
+        addTestItem(new TestItem("40", "Test 40", TestGenericDetailFragment.class));
+    }
+
+    private static void addTestItem(TestItem item) {
+        ITEMS.add(item);
+        ITEM_MAP.put(item.mId, item);
+    }
+
+    public static List<TestItem> getTests() {
+        return ITEMS;
+    }
+
+    public static TestItem getTest(String id) {
+        return ITEM_MAP.get(id);
+    }
+
+    public static TestItem getTest(int pos) {
+        return ITEMS.get(pos);
+    }
+
+    public static Fragment getFragment(String id) {
+        try {
+            Fragment fragment = getTest(id).mClassFragment.newInstance();
+            Bundle arguments = new Bundle();
+            arguments.putString("item_id", id);
+            fragment.setArguments(arguments);
+            return fragment;
+        } catch (InstantiationException e) {
+            Log.e(LOG_TAG, "Exception", e);
+            return null;
+        } catch (IllegalAccessException e) {
+            Log.e(LOG_TAG, "Exception", e);
+            return null;
+        }
+    }
+}
diff --git a/tests/uiautomator/app/src/com/android/uiautomator/app/TestListFragment.java b/tests/uiautomator/app/src/com/android/uiautomator/app/TestListFragment.java
new file mode 100644
index 0000000..ba981cb
--- /dev/null
+++ b/tests/uiautomator/app/src/com/android/uiautomator/app/TestListFragment.java
@@ -0,0 +1,105 @@
+/*
+ * 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.uiautomator.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class TestListFragment extends ListFragment {
+
+    private static final String STATE_ACTIVATED_POSITION = "activated_position";
+
+    private Callbacks mCallbacks = sDummyCallbacks;
+    private int mActivatedPosition = ListView.INVALID_POSITION;
+
+    public interface Callbacks {
+
+        public void onItemSelected(String id);
+    }
+
+    private static Callbacks sDummyCallbacks = new Callbacks() {
+        @Override
+        public void onItemSelected(String id) {
+        }
+    };
+
+    public TestListFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setListAdapter(new ArrayAdapter<TestItems.TestItem>(getActivity(),
+                R.layout.simple_list_item_selected, R.id.label, TestItems.getTests()));
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedState) {
+        super.onViewCreated(view, savedState);
+        if (savedState != null && savedState.containsKey(STATE_ACTIVATED_POSITION)) {
+            setActivatedPosition(savedState.getInt(STATE_ACTIVATED_POSITION));
+        }
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        if (!(activity instanceof Callbacks)) {
+            throw new IllegalStateException("Activity must implement fragment's callbacks.");
+        }
+
+        mCallbacks = (Callbacks) activity;
+    }
+
+    @Override
+    public void onDetach() {
+        super.onDetach();
+        mCallbacks = sDummyCallbacks;
+    }
+
+    @Override
+    public void onListItemClick(ListView listView, View view, int position, long id) {
+        super.onListItemClick(listView, view, position, id);
+        mCallbacks.onItemSelected(TestItems.getTest(position).mId);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        if (mActivatedPosition != ListView.INVALID_POSITION) {
+            outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
+        }
+    }
+
+    public void setActivateOnItemClick(boolean activateOnItemClick) {
+        getListView().setChoiceMode(
+                activateOnItemClick ? ListView.CHOICE_MODE_SINGLE : ListView.CHOICE_MODE_NONE);
+    }
+
+    public void setActivatedPosition(int position) {
+        if (position == ListView.INVALID_POSITION) {
+            getListView().setItemChecked(mActivatedPosition, false);
+        } else {
+            getListView().setItemChecked(position, true);
+        }
+
+        mActivatedPosition = position;
+    }
+}
diff --git a/tests/uiautomator/src/com/android/cts/uiautomatortest/CtsUiAutomatorTest.java b/tests/uiautomator/src/com/android/cts/uiautomatortest/CtsUiAutomatorTest.java
deleted file mode 100644
index 7e4c367..0000000
--- a/tests/uiautomator/src/com/android/cts/uiautomatortest/CtsUiAutomatorTest.java
+++ /dev/null
@@ -1,1072 +0,0 @@
-/*
- * 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.uiautomatortest;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.uiautomator.core.UiCollection;
-import com.android.uiautomator.core.UiDevice;
-import com.android.uiautomator.core.UiObject;
-import com.android.uiautomator.core.UiObjectNotFoundException;
-import com.android.uiautomator.core.UiScrollable;
-import com.android.uiautomator.core.UiSelector;
-import com.android.uiautomator.core.UiWatcher;
-import com.android.uiautomator.testrunner.UiAutomatorTestCase;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Sanity test uiautomator functionality on target device.
- */
-public class CtsUiAutomatorTest extends UiAutomatorTestCase {
-    private static final String LOG_TAG = CtsUiAutomatorTest.class.getSimpleName();
-    private static final String[] LIST_SCROLL_TESTS = new String[] {
-            "Test 17", "Test 11", "Test 20", "Test 35"
-    };
-    private static final String LAUNCH_APP = "am start -a android.intent.action.MAIN"
-            + " -n com.android.cts.uiautomator/.MainActivity -W";
-    private static final String PKG_NAME = "com.android.cts.uiautomator";
-
-    // Maximum wait for key object to become visible
-    private static final int WAIT_EXIST_TIMEOUT = 5 * 1000;
-
-    private static final String SCREEN_SHOT_FILE_PATH_NAME = "/data/local/tmp/ctsScreenShot";
-
-    // Should match the value defined in UiObject
-    private static final int FINGER_TOUCH_HALF_WIDTH = 20;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // Make sure the test app is always running
-        UiDevice.getInstance().waitForIdle();
-        if (!new UiObject(new UiSelector().packageName(PKG_NAME)).exists())
-            runShellCommand(LAUNCH_APP);
-    }
-
-    /**
-     * Helper to execute a command on the shell
-     *
-     * @throws IOException
-     * @throws InterruptedException
-     */
-    private void runShellCommand(String command) throws IOException, InterruptedException {
-        Process p = null;
-        BufferedReader resultReader = null;
-        try {
-            p = Runtime.getRuntime().exec(command);
-            int status = p.waitFor();
-            if (status != 0) {
-                throw new RuntimeException(String.format("Run shell command: %s, status: %s",
-                        command, status));
-            }
-        } finally {
-            if (resultReader != null) {
-                resultReader.close();
-            }
-            if (p != null) {
-                p.destroy();
-            }
-        }
-    }
-
-    /*
-     * Items in the listScrollTests array should be spread out such that a
-     * scroll is required to reach each item at each of the far ends.
-     */
-    public void testListScrollAndSelect() throws UiObjectNotFoundException {
-        UiScrollable listView = new UiScrollable(
-                new UiSelector().className(android.widget.ListView.class.getName()));
-
-        // on single fragment display
-        if (!listView.exists())
-            UiDevice.getInstance().pressBack();
-
-        for (String test : LIST_SCROLL_TESTS) {
-            openTest(test);
-            verifyTestDetailsExists(test);
-        }
-    }
-
-    /**
-     * Test erasing of multi word text in edit field and input of new text. Test
-     * verifying input text using a complex UiSelector
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testTextEraseAndInput() throws UiObjectNotFoundException {
-        String testText = "Android Ui Automator Input Text";
-        openTest("Test 1");
-
-        UiObject editText = new UiObject(new UiSelector().className(android.widget.EditText.class
-                .getName()));
-        editText.setText(testText);
-
-        UiObject submitButton = new UiObject(new UiSelector()
-                .className(android.widget.Button.class.getName()).clickable(true)
-                .textStartsWith("Submit"));
-        submitButton.click();
-
-        UiObject result = new UiObject(new UiSelector().className(
-                android.widget.LinearLayout.class.getName()).childSelector(
-                (new UiSelector().className(android.widget.ScrollView.class.getName())
-                        .childSelector(new UiSelector().className(android.widget.TextView.class
-                                .getName())))));
-
-        if (!testText.equals(result.getText())) {
-            throw new UiObjectNotFoundException("Test text: " + testText);
-        }
-
-        getObjectByText("OK").click();
-    }
-
-    /**
-     * Select each of the buttons by using only the content description property
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectByContentDescription() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        getObjectByDescription("Button 1").click();
-        verifyDialogActionResults("Button 1");
-        getObjectByDescription("Button 2").click();
-        verifyDialogActionResults("Button 2");
-        getObjectByDescription("Button 3").click();
-        verifyDialogActionResults("Button 3");
-    }
-
-    /**
-     * Select each of the buttons by using only the text property
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectByText() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        getObjectByText("Button 1").click();
-        verifyDialogActionResults("Button 1");
-        getObjectByText("Button 2").click();
-        verifyDialogActionResults("Button 2");
-        getObjectByText("Button 3").click();
-        verifyDialogActionResults("Button 3");
-    }
-
-    /**
-     * Select each of the buttons by using only the index property
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectByIndex() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        getObjectByIndex(android.widget.Button.class.getName(), 0).click();
-        verifyDialogActionResults("Button 1");
-        getObjectByIndex(android.widget.Button.class.getName(), 1).click();
-        verifyDialogActionResults("Button 2");
-        getObjectByIndex(android.widget.Button.class.getName(), 2).click();
-        verifyDialogActionResults("Button 3");
-    }
-
-    /**
-     * Select each of the buttons by using only the instance number
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectByInstance() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        getObjectByInstance(android.widget.Button.class.getName(), 0).click();
-        verifyDialogActionResults("Button 1");
-        getObjectByInstance(android.widget.Button.class.getName(), 1).click();
-        verifyDialogActionResults("Button 2");
-        getObjectByInstance(android.widget.Button.class.getName(), 2).click();
-        verifyDialogActionResults("Button 3");
-    }
-
-    /**
-     * Test when a node's state is changed due to an action, it is updated in the accessibility
-     * hierarchy.
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectAfterContentChanged() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        UiObject dynaButton = getObjectByText("Before");
-        dynaButton.click();
-        assertTrue("Button state change is not refreshed in accessibility hierarchy",
-                getObjectByText("After").exists());
-    }
-
-    /**
-     * Test opening the options menu using the soft buttons
-     *
-     * @throws UiObjectNotFoundException
-     * @throws InterruptedException
-     * @throws IOException
-     */
-    public void testDeviceSoftKeys() throws UiObjectNotFoundException, IOException,
-            InterruptedException {
-        openTest("Test 2");
-        UiDevice device = UiDevice.getInstance();
-        device.pressMenu();
-        getObjectByText("Finish").click();
-        verifyDialogActionResults("Finish");
-
-        // Back button
-        openTest("Test 1");
-        UiObject editText = new UiObject(new UiSelector().className(android.widget.EditText.class
-                .getName()));
-        editText.setText("Android Geppetto Test Application");
-
-        UiObject submitButton = new UiObject(new UiSelector()
-                .className(android.widget.Button.class.getName()).clickable(true)
-                .textStartsWith("Submit"));
-        submitButton.click();
-
-        // Text from the popup dialog
-        UiObject result = new UiObject(new UiSelector().textContains("geppetto"));
-
-        // Back button test to dismiss the dialog
-        assertTrue("Wait for exist must return true", result.waitForExists(2000));
-        device.pressBack();
-        result.waitUntilGone(1000);
-        assertFalse("Wait for exist must return false after press back", result.exists());
-
-        // Home button test
-        openTest("Test 5");
-        String pkgName = device.getCurrentPackageName();
-        assertTrue("CTS test app must be running", pkgName.equals(PKG_NAME));
-        device.pressHome();
-        boolean gone = new UiObject(new UiSelector().packageName(PKG_NAME)).waitUntilGone(5000);
-        assertTrue("CTS test app still visble after pressing home", gone);
-    }
-
-    /**
-     * This view is in constant update generating window content changed events.
-     * The test will read the time displayed and exhaust each wait for idle
-     * timeout until it read and sets the text back into the edit field and
-     * presses submit. A dialog box should pop up with the time it took since
-     * reading the value until pressing submit.
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testWaitForIdleTimeout() throws UiObjectNotFoundException {
-        openTest("Test 3");
-        UiObject clk = new UiObject(new UiSelector().descriptionStartsWith("Performance "));
-
-        // First default wait for idle timeout assumed to be 10 seconds
-        String txtTime = clk.getText();
-        UiObject edit = new UiObject(new UiSelector().className(android.widget.EditText.class
-                .getName()));
-
-        // Second default wait for idle timeout assumed to be 10 seconds.
-        // Total ~20.
-        edit.setText(txtTime);
-
-        // Third default wait for idle timeout assumed to be 10 seconds.
-        // Total ~30.
-        getObjectByText("Submit").click();
-
-        // The value read should have value between 30 and 60 seconds indicating
-        // that the internal default timeouts for wait-for-idle is in acceptable
-        // range.
-        UiObject readTime = new UiObject(new UiSelector().className(
-                android.widget.TextView.class.getName()).instance(1));
-        String timeDiff = readTime.getText();
-        Log.i(LOG_TAG, "Sync time: " + timeDiff);
-
-        getObjectByText("OK").click();
-
-        int totalDelay = Integer.parseInt(timeDiff);
-
-        // Cumulative waits in this test should add up to at minimum 30 seconds
-        assertFalse("Timeout for wait-for-idle is too short. Expecting minimum 30 seconds",
-                totalDelay < 30 * 1000);
-
-        // allow for tolerance in time measurements due to differences between
-        // device speeds
-        assertFalse("Timeout for wait-for-idle is too long. Expecting maximum 60 seconds",
-                totalDelay > 60 * 1000);
-    }
-
-    /**
-     * This view is in constant update generating window content changed events.
-     * This test uses the soft key presses and clicks while the background
-     * screen is constantly updating causing a constant busy state.
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testVerifyMenuClicks() throws UiObjectNotFoundException {
-        openTest("Test 3");
-        UiDevice.getInstance().pressMenu();
-        new UiObject(new UiSelector().text("Submit")).click();
-        verifyDialogActionResults("Submit");
-        UiDevice.getInstance().pressMenu();
-        new UiObject(new UiSelector().text("Exit")).click();
-        verifyDialogActionResults("Exit");
-    }
-
-    /**
-     * Verifies swipeRight, swipeLeft and raw swipe APIs perform as expected.
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSwipes() throws UiObjectNotFoundException {
-        openTest("Test 4");
-        UiObject textView = new UiObject(new UiSelector().textContains("["));
-
-        textView.swipeLeft(10);
-        assertTrue("UiObject swipe left 1->2", "[ 2 ]".equals(textView.getText()));
-
-        textView.swipeLeft(10);
-        assertTrue("UiObject swipe left 2->3", "[ 3 ]".equals(textView.getText()));
-
-        textView.swipeLeft(10);
-        assertTrue("UiObject swipe left 3->4", "[ 4 ]".equals(textView.getText()));
-
-        textView.swipeRight(10);
-        assertTrue("UiObject swipe right 3<-4", "[ 3 ]".equals(textView.getText()));
-
-        textView.swipeRight(10);
-        assertTrue("UiObject swipe right 2<-3", "[ 2 ]".equals(textView.getText()));
-
-        textView.swipeRight(10);
-        assertTrue("UiObject swipe right 1<-2", "[ 1 ]".equals(textView.getText()));
-
-        Rect tb = textView.getBounds();
-        UiDevice.getInstance().swipe(tb.right - 20, tb.centerY(), tb.left + 20, tb.centerY(), 50);
-
-        SystemClock.sleep(100);
-        assertTrue("UiDevice raw swipe 1->2", "[ 2 ]".equals(textView.getText()));
-    }
-
-    /**
-     * Creates a complex selector
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testComplexSelectors() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiSelector frameLayout = new UiSelector().className(android.widget.FrameLayout.class
-                .getName());
-        UiSelector gridLayout = new UiSelector().className(android.widget.GridLayout.class
-                .getName());
-        UiSelector toggleButton = new UiSelector().className(android.widget.ToggleButton.class
-                .getName());
-        UiObject button = new UiObject(frameLayout.childSelector(gridLayout).childSelector(
-                toggleButton));
-
-        assertTrue("Toggle button value should be OFF", "OFF".equals(button.getText()));
-        button.click();
-        assertTrue("Toggle button value should be ON", "ON".equals(button.getText()));
-        button.click();
-        assertTrue("Toggle button value should be OFF", "OFF".equals(button.getText()));
-    }
-
-    /**
-     * Test when an object does not exist, an exception is thrown
-     * @throws UiObjectNotFoundException
-     */
-    public void testExceptionObjectNotFound() throws UiObjectNotFoundException {
-        UiSelector selector = new UiSelector().text("Nothing should be found");
-        UiSelector child = new UiSelector().className("Nothing");
-        UiObject obj = new UiObject(selector.childSelector(child));
-
-        assertFalse("Object is reported as existing", obj.exists());
-
-        try {
-            obj.click();
-        } catch (UiObjectNotFoundException e) {
-            return;
-        }
-        assertTrue("Exception not thrown for Object not found", false);
-    }
-
-    /**
-     * Verifies the UiWatcher registration and trigger function
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testUiWatcher() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiDevice device = UiDevice.getInstance();
-        device.registerWatcher("Artificial crash", new UiWatcher() {
-
-            @Override
-            public boolean checkForCondition() {
-                if (new UiObject(new UiSelector().packageName("android")).exists()) {
-                    try {
-                        // Expecting a localized OK button
-                        new UiObject(new UiSelector().className(
-                                android.widget.Button.class.getName()).enabled(true)).click();
-                    } catch (UiObjectNotFoundException e) {
-                    }
-                    return true;
-                }
-                return false;
-            }
-        });
-
-        // Causes a runtime exception to be thrown
-        getObjectByText("Button").click();
-
-        // Fake doing something while the exception is being displayed
-        SystemClock.sleep(2000);
-        device.runWatchers();
-        assertTrue("UiWatcher not triggered", device.hasAnyWatcherTriggered());
-    }
-
-    /**
-     * Verifies the 'checked' property of both UiSelector and UiObject
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectorChecked() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiObject checkboxChecked = new UiObject(new UiSelector().className(
-                android.widget.CheckBox.class.getName()).checked(true));
-        UiObject checkboxNotChecked = new UiObject(new UiSelector().className(
-                android.widget.CheckBox.class.getName()).checked(false));
-
-        checkboxNotChecked.click();
-        assertTrue("Checkbox should be checked", checkboxChecked.isChecked());
-        checkboxChecked.click();
-        assertFalse("Checkbox should be unchecked", checkboxNotChecked.isChecked());
-    }
-
-    /**
-     * Verifies the 'Clickable' property of both the UiSelector and UiObject
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectorClickable() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiSelector clickableCheckbox = new UiSelector().clickable(true).className(
-                android.widget.CheckBox.class.getName());
-        UiSelector notClickableProgress = new UiSelector().clickable(false).className(
-                android.widget.ProgressBar.class.getName());
-
-        assertTrue("Selector clickable", new UiObject(clickableCheckbox).isClickable());
-        assertFalse("Selector not clickable", new UiObject(notClickableProgress).isClickable());
-    }
-
-    /**
-     * Verifies the 'focusable' property of both UiSelector and UiObject
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectorFocusable() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiSelector mainLayout = new UiSelector().description("Widgets Collection");
-        UiSelector focusableCheckbox = mainLayout.childSelector(new UiSelector().className(
-                android.widget.CheckBox.class.getName()).focusable(true));
-        UiSelector notFocusableSpinner = mainLayout.childSelector(new UiSelector().className(
-                android.widget.Spinner.class.getName()).focusable(false));
-
-        assertTrue("Selector focusable", new UiObject(focusableCheckbox).isFocusable());
-        assertFalse("Selector not focusable", new UiObject(notFocusableSpinner).isFocusable());
-    }
-
-    /**
-     * Verifies the 'DescriptionContains' property of UiSelector
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectorDescriptionContains() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiSelector progressDescriptionContains = new UiSelector().descriptionContains("%");
-        assertTrue("Selector descriptionContains", "Progress is 50 %".equals(new UiObject(
-                progressDescriptionContains).getContentDescription()));
-    }
-
-    /**
-     * Verifies the 'DescriptionStarts' property of UiSelector
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectorDescriptionStarts() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiSelector progressDescriptionStart = new UiSelector().descriptionStartsWith("progress");
-        assertTrue("Selector descriptionStart", "Progress is 50 %".equals(new UiObject(
-                progressDescriptionStart).getContentDescription()));
-    }
-
-    /**
-     * Verifies the 'Enabled' property of both UiSelector and UiObject
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testSelectorEnabled() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiSelector mainLayout = new UiSelector().description("Widgets Collection");
-        UiSelector buttonDisabled = mainLayout.childSelector(new UiSelector().className(
-                android.widget.Button.class.getName()).enabled(false));
-        UiSelector buttonEnabled = mainLayout.childSelector(new UiSelector().className(
-                android.widget.Button.class.getName()).enabled(true));
-
-        assertFalse("Selector enabled false", new UiObject(buttonDisabled).isEnabled());
-        assertTrue("Selector enabled true", new UiObject(buttonEnabled).isEnabled());
-    }
-
-    /**
-     * Verifies the UiCollection object child counting by object pattern
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testCollectionCount() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiCollection collection = new UiCollection(
-                new UiSelector().description("Widgets Collection"));
-        assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
-
-        assertTrue("Collection count",
-                collection.getChildCount(new UiSelector().clickable(true)) == 6);
-    }
-
-    /**
-     * Verifies the UiCollection can find an object by text and returning by
-     * pattern
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testCollectionGetChildByText() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiCollection collection = new UiCollection(
-                new UiSelector().description("Widgets Collection"));
-        assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
-
-        UiObject item = collection.getChildByText(
-                new UiSelector().className(android.widget.Button.class.getName()), "Button");
-
-        assertTrue("Collection get child by text", "Button".equals(item.getText()));
-    }
-
-    /**
-     * Verifies the UiCollection can find an object by instance and returning by
-     * pattern
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testCollectionGetChildByInstance() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiCollection collection = new UiCollection(
-                new UiSelector().description("Widgets Collection"));
-        assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
-
-        // find the second button
-        UiObject item = collection.getChildByInstance(
-                new UiSelector().className(android.widget.Button.class.getName()), 1);
-
-        assertTrue("Collection get child by instance", "Button".equals(item.getText()));
-    }
-
-    /**
-     * Verifies the UiCollection can find an object by description and returning
-     * by pattern
-     *
-     * @throws UiObjectNotFoundException
-     */
-    public void testCollectionGetChildByDescription() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiCollection collection = new UiCollection(
-                new UiSelector().description("Widgets Collection"));
-        assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
-
-        UiObject item = collection.getChildByDescription(
-                new UiSelector().className(android.widget.Button.class.getName()),
-                "Description for Button");
-
-        assertTrue("Collection get child by description", "Button".equals(item.getText()));
-    }
-
-    /**
-     * Test Orientation APIs by causing rotations and verifying current state
-     *
-     * @throws RemoteException
-     * @throws UiObjectNotFoundException
-     * @since API Level 17
-     */
-    public void testRotation() throws RemoteException, UiObjectNotFoundException {
-        openTest("Test 5");
-        UiDevice device = UiDevice.getInstance();
-
-        device.setOrientationLeft();
-        device.waitForIdle(); // isNaturalOrientation is not waiting for idle
-        SystemClock.sleep(1000);
-        assertFalse("Device orientation should not be natural", device.isNaturalOrientation());
-
-        device.setOrientationNatural();
-        device.waitForIdle(); // isNaturalOrientation is not waiting for idle
-        SystemClock.sleep(1000);
-        assertTrue("Device orientation should be natural", device.isNaturalOrientation());
-
-        device.setOrientationRight();
-        device.waitForIdle(); // isNaturalOrientation is not waiting for idle
-        SystemClock.sleep(1000);
-        assertFalse("Device orientation should not be natural", device.isNaturalOrientation());
-
-        device.setOrientationNatural();
-    }
-
-    /**
-     * Reads the current device's product name. Since it is not possible to predetermine the
-     * would be value, the check verifies that the value is not null and not empty.
-     *
-     * @since API Level 17
-     */
-    public void testGetProductName() {
-        String name = UiDevice.getInstance().getProductName();
-        assertFalse("Product name check returned empty string", name.isEmpty());
-    }
-
-    /**
-     * Select each of the buttons by using only regex text
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 17
-     */
-    public void testSelectByTextMatch() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        getObjectByTextMatch(".*n\\s1$").click();
-        verifyDialogActionResults("Button 1");
-        getObjectByTextMatch(".*n\\s2$").click();
-        verifyDialogActionResults("Button 2");
-        getObjectByTextMatch(".*n\\s3$").click();
-        verifyDialogActionResults("Button 3");
-    }
-
-    /**
-     * Select each of the buttons by using only regex content-description
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 17
-     */
-    public void testSelectByDescriptionMatch() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        getObjectByDescriptionMatch(".*n\\s1$").click();
-        verifyDialogActionResults("Button 1");
-        getObjectByDescriptionMatch(".*n\\s2$").click();
-        verifyDialogActionResults("Button 2");
-        getObjectByDescriptionMatch(".*n\\s3$").click();
-        verifyDialogActionResults("Button 3");
-    }
-
-    /**
-     * Select each of the buttons by using only regex class name
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 17
-     */
-    public void testSelectByClassMatch() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiObject tgl = getObjectByClassMatch(".*ToggleButton$", 0);
-        String tglValue = tgl.getText();
-        tgl.click();
-
-        assertFalse("Matching class by Regex failed", tglValue.equals(tgl.getText()));
-    }
-
-    /**
-     * Select each of the buttons by using only class type
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 17
-     */
-    public void testSelectByClassType() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiObject tgl = getObjectByClass(android.widget.ToggleButton.class, 0);
-        String tglValue = tgl.getText();
-        tgl.click();
-
-        assertFalse("Matching class by class type failed", tglValue.equals(tgl.getText()));
-    }
-
-    /**
-     * Test the coordinates of 3 buttons side by side verifying vertical and
-     * horizontal coordinates.
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 17
-     */
-    public void testGetVisibleBounds() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        Rect rect1 = getObjectByText("Button 1").getVisibleBounds();
-        Rect rect2 = getObjectByText("Button 2").getVisibleBounds();
-        Rect rect3 = getObjectByText("Button 3").getVisibleBounds();
-
-        assertTrue("X coordinate check failed",
-                rect1.left < rect2.left && rect2.right < rect3.right);
-        assertTrue("Y coordinate check failed",
-                rect1.top == rect2.top && rect2.bottom == rect3.bottom);
-    }
-
-   /**
-     * Tests the LongClick functionality in the API
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 17
-     */
-    public void testSelectorLongClickable() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        getObjectByText("Button 1").longClick();
-        verifyDialogActionResults("Longclick Button 1");
-    }
-
-    /**
-     * Test the UiSelector's long-clickable property
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 17
-     */
-    public void testSelectorLongClickableProperty() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        UiObject button3 = new UiObject(new UiSelector().className(
-                android.widget.Button.class).longClickable(true).instance(2));
-        button3.longClick();
-        verifyDialogActionResults("Longclick Button 3");
-    }
-
-    /**
-     * Takes a screen shot of the current display and checks if the file is
-     * created and is not zero size.
-     *
-     * @since API Level 17
-     */
-    public void testTakeScreenShots() {
-        File storePath = new File(SCREEN_SHOT_FILE_PATH_NAME);
-        getUiDevice().takeScreenshot(storePath);
-
-        assertTrue("Screenshot file not detected in store", storePath.exists());
-        assertTrue("Zero size for screenshot file", storePath.length() > 0);
-    }
-
-    /**
-     * Verifies the 'Resource-Id' property of UiSelector
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 18
-     */
-    public void testSelectorResourceId() throws UiObjectNotFoundException {
-        openTest("Test 5");
-        UiSelector toggleSelector =
-                new UiSelector().resourceId("com.android.cts.uiautomator:id/test_5_toggleButton");
-        UiObject toggleButton = new UiObject(toggleSelector);
-        assertTrue("Object with selector resource-id not found", toggleButton.exists());
-        assertTrue("Incorrect object for selector resource-id returned",
-                "OFF".equals(toggleButton.getText()) || "ON".equals(toggleButton.getText()));
-    }
-
-    /**
-     * Verify the UiSelector property resourceIdMatches
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 18
-     */
-    public void testSelectorResourceIdMatches() throws UiObjectNotFoundException {
-        openTest("Test 2");
-        new UiObject(new UiSelector().resourceIdMatches("(?i).*button.*").instance(2)).click();
-        verifyDialogActionResults("Button 3");
-        new UiObject(new UiSelector().resourceIdMatches("(?i).*button1.*")).click();
-        verifyDialogActionResults("Button 1");
-    }
-
-    /**
-     * Performs a pinch out from the center of a view to its edges and listens to
-     * the motion events to make sure the starting and ending points of both pointers
-     * are correct.
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 18
-     */
-    public void testPinchOut() throws UiObjectNotFoundException {
-        openTest("Test 12");
-
-        UiObject screen = new UiObject(
-                new UiSelector().description("Details View"));
-
-        // get the current view dimensions
-        Rect screenRect = screen.getBounds();
-
-        // perform the pinch for 100% of the view dimensions starting form
-        // the center out to the edges.
-        screen.pinchOut(100, 30);
-
-        // dialog with the detected pointers motion coordinates is displayed.
-        UiObject results = new UiObject(new UiSelector().className(
-                android.widget.ScrollView.class).childSelector(new UiSelector().className(
-                        android.widget.TextView.class)));
-        String allPointers = results.getText();
-        new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
-
-        // parse pointer 1
-        Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
-        Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
-        // parse pointer 2
-        Point p2s = parsePointerCoordinates(allPointers, 1, 0); // start
-        Point p2e = parsePointerCoordinates(allPointers, 1, 1); // end
-
-        assertTrue("All Y axis coordinates for pointer 1 must be the same", p1s.y == p1e.y);
-        assertTrue("All Y axis coordinates for pointer 2 must be the same", p2s.y == p2e.y);
-        assertTrue("All Y axis coordinates for both pointers must be the same", p1s.y == p2s.y);
-        assertTrue("Pinch must be in center of target view", p2s.y == screenRect.centerY());
-
-        assertTrue("Touch-down X coordinate for pointer 1 is invalid",
-                withinMarginOfError(0.125f, screenRect.centerX(), p1s.x));
-
-        assertTrue("Touch-down X coordinate for pointer 2 is invalid",
-                withinMarginOfError(0.125f, screenRect.centerX(), p2s.x));
-
-        assertTrue("Touch-up X coordinate for pointer 1 is invalid",
-                withinMarginOfError(0.125f, screenRect.centerX() - screenRect.left,
-                        screenRect.centerX() - p1e.x));
-
-        assertTrue("Touch-up X coordinate for pointer 2 is invalid",
-                withinMarginOfError(0.125f, screenRect.right, p2e.x));
-    }
-
-    /**
-     * Performs a pinch in from the edges of a view to its center and listens to
-     * the motion events to make sure the starting and ending points of both pointers
-     * are correct.
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 18
-     */
-    public void testPinchIn() throws UiObjectNotFoundException {
-        openTest("Test 12");
-
-        UiObject screen = new UiObject(
-                new UiSelector().description("Details View"));
-
-        // get the current view dimensions
-        Rect screenRect = screen.getBounds();
-
-        // perform the pinch for 100% of the view dimensions starting form
-        // the edges in towards the center.
-        screen.pinchIn(100, 30);
-
-        // dialog with the detected pointers motion coordinates is displayed.
-        UiObject results = new UiObject(new UiSelector().className(
-                android.widget.ScrollView.class).childSelector(new UiSelector().className(
-                        android.widget.TextView.class)));
-        String allPointers = results.getText();
-        new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
-
-        // parse pointer 1
-        Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
-        Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
-        // parse pointer 2
-        Point p2s = parsePointerCoordinates(allPointers, 1, 0); // start
-        Point p2e = parsePointerCoordinates(allPointers, 1, 1); // end
-
-        assertTrue("All Y axis coordinates for pointer 1 must be the same", p1s.y == p1e.y);
-        assertTrue("All Y axis coordinates for pointer 2 must be the same", p2s.y == p2e.y);
-        assertTrue("All Y axis coordinates for both pointers must be the same", p1s.y == p2s.y);
-        assertTrue("Pinch must be in center of target view", p2s.y == screenRect.centerY());
-
-        assertTrue("Touch-down X coordinate for pointer 1 is invalid",
-                withinMarginOfError(0.125f, screenRect.centerX() - screenRect.left,
-                        screenRect.centerX() -  p1s.x));
-
-        assertTrue("Touch-down X coordinate for pointer 2 is invalid",
-                withinMarginOfError(0.125f, screenRect.right, p2s.x));
-
-        assertTrue("Touch-up X coordinate for pointer 1 is invalid",
-                withinMarginOfError(0.125f, screenRect.centerX() - FINGER_TOUCH_HALF_WIDTH, p1e.x));
-
-        assertTrue("Touch-up X coordinate for pointer 2 is invalid",
-                withinMarginOfError(0.125f, screenRect.centerX() + FINGER_TOUCH_HALF_WIDTH, p2e.x));
-    }
-
-    /**
-     * Performs a drag and drop operation from one UiObject to another UiObject
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 18
-     */
-    public void testDragToObject() throws UiObjectNotFoundException {
-        openTest("Test 5");
-
-        UiObject imageButton = new UiObject(new UiSelector().description("Image button"));
-        UiObject starsBar = new UiObject(new UiSelector().className(android.widget.RatingBar.class));
-
-        Rect starsBarRect = starsBar.getBounds();
-        Rect imageButtonRect = imageButton.getBounds();
-        imageButton.dragTo(starsBar, 30);
-
-        // dialog with the detected pointers motion coordinates is displayed.
-        UiObject results = new UiObject(new UiSelector().className(
-                android.widget.ScrollView.class).childSelector(new UiSelector().className(
-                        android.widget.TextView.class)));
-        String allPointers = results.getText();
-        new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
-
-        // parse pointer 1
-        Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
-        Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
-
-        assertTrue("Invalid touch starting.X reported",
-                withinMarginOfError(0.05f, imageButtonRect.centerX(), p1s.x));
-        assertTrue("Invalid touch starting.Y reported",
-                withinMarginOfError(0.05f, imageButtonRect.centerY(), p1s.y));
-        assertTrue("Invalid touch ending.X reported",
-                withinMarginOfError(0.05f, starsBarRect.centerX(), p1e.x));
-        assertTrue("Invalid touch ending.Y reported",
-                withinMarginOfError(0.05f, starsBarRect.centerY(), p1e.y));
-    }
-
-    /**
-     * Performs a drag and drop operation from one UiObject to a specified coordinates
-     *
-     * @throws UiObjectNotFoundException
-     * @since API Level 18
-     */
-   public void testDragToCoordinates() throws UiObjectNotFoundException {
-       openTest("Test 5");
-
-       UiObject imageButton = new UiObject(new UiSelector().description("Image button"));
-       UiObject starsBar = new UiObject(new UiSelector().className(android.widget.RatingBar.class));
-
-       Rect starsBarRect = starsBar.getBounds();
-       Rect imageButtonRect = imageButton.getBounds();
-       imageButton.dragTo(starsBarRect.centerX(), starsBarRect.centerY(), 30);
-
-       // dialog with the detected pointers motion coordinates is displayed.
-       UiObject results = new UiObject(new UiSelector().className(
-               android.widget.ScrollView.class).childSelector(new UiSelector().className(
-                       android.widget.TextView.class)));
-       String allPointers = results.getText();
-       new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
-
-       // parse pointer 1
-       Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
-       Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
-
-       assertTrue("Invalid touch starting.X reported",
-               withinMarginOfError(0.05f, imageButtonRect.centerX(), p1s.x));
-       assertTrue("Invalid touch starting.Y reported",
-               withinMarginOfError(0.05f, imageButtonRect.centerY(), p1s.y));
-       assertTrue("Invalid touch ending.X reported",
-               withinMarginOfError(0.05f, starsBarRect.centerX(), p1e.x));
-       assertTrue("Invalid touch ending.Y reported",
-               withinMarginOfError(0.05f, starsBarRect.centerY(), p1e.y));
-   }
-
-   /**
-    * Detect if actual value is within the allowable margin of error of the expected value.
-    *
-    * Used essentially with actual values that may vary from the expected values such in the
-    * cases of touch and pinch and touch and swipe where the starting or ending points may
-    * not exactly match the expected value.
-    *
-    * @param marginPrecent is values between 0 and 1
-    * @param expected
-    * @param actual
-    * @return true if actual is within the allowed range from expected
-    */
-   private boolean withinMarginOfError(float marginPrecent, int expected, int actual) {
-       int m = (int) (marginPrecent * expected);
-       return actual >= expected - m && actual <= expected + m;
-   }
-
-   /**
-     * Parses a string containing starting to ending coordinates of one or more pointers.
-     *
-     * @param allPointers is a raw string with coordinates from all detected pointers
-     * @param pointerNumber is the desired pointer to be parsed
-     * @param edge is the 0 for the start or 1 for the end of the swipe
-     * @return Point containing the start or end coordinates of the specified pointer number
-     */
-    private Point parsePointerCoordinates(String allPointers, int pointerNumber, int edge) {
-        String pointers[] = allPointers.split("\n");
-        String coordinates = pointers[pointerNumber].split(":")[edge];
-        String xy[] = coordinates.split(",");
-        return new Point(Integer.parseInt(xy[0]), Integer.parseInt(xy[1]));
-    }
-
-    /**
-     * Private helper to open test views. Also covers UiScrollable tests
-     *
-     * @param name
-     * @throws UiObjectNotFoundException
-     */
-    private void openTest(String name) throws UiObjectNotFoundException {
-        try {
-            UiDevice.getInstance().setOrientationNatural();
-        } catch (RemoteException e) {
-            // will catch it in its own test. For now try to put the device
-            // in its natural orientation prior to each test
-        }
-        UiScrollable listView = new UiScrollable(
-                new UiSelector().className(android.widget.ListView.class.getName()));
-
-        // on single fragment display
-        if (!listView.exists())
-            UiDevice.getInstance().pressBack();
-
-        UiObject testItem = listView.getChildByText(
-                new UiSelector().className(android.widget.TextView.class.getName()), name);
-
-        testItem.click();
-    }
-
-    private void verifyTestDetailsExists(String name) throws UiObjectNotFoundException {
-        // verify that we're at the right test
-        new UiObject(new UiSelector().description("Details").text(name)).getText();
-    }
-
-    private UiObject getObjectByText(String txt) {
-        return new UiObject(new UiSelector().text(txt));
-    }
-
-    private UiObject getObjectByTextMatch(String regex) {
-        return new UiObject(new UiSelector().textMatches(regex));
-    }
-
-    private UiObject getObjectByDescriptionMatch(String regex) {
-        return new UiObject(new UiSelector().descriptionMatches(regex));
-    }
-
-    private UiObject getObjectByDescription(String txt) {
-        return new UiObject(new UiSelector().description(txt));
-    }
-
-    private UiObject getObjectByClassMatch(String regex, int instance) {
-        return new UiObject(new UiSelector().classNameMatches(regex).instance(instance));
-    }
-
-    private <T> UiObject getObjectByClass(Class<T> type, int instance) {
-        return new UiObject(new UiSelector().className(type).instance(instance));
-    }
-
-    private UiObject getObjectByIndex(String className, int index) {
-        return new UiObject(new UiSelector().className(className).index(index));
-    }
-
-    private UiObject getObjectByInstance(String className, int instance) {
-        return new UiObject(new UiSelector().className(className).instance(instance));
-    }
-
-    private void verifyDialogActionResults(String txt) throws UiObjectNotFoundException {
-        if (!getObjectByText("Action results").exists() || !getObjectByText(txt).exists()) {
-            throw new UiObjectNotFoundException(txt);
-        }
-        getObjectByText("OK").click();
-    }
-}
diff --git a/tests/uiautomator/src/com/android/uiautomator/cts/UiAutomatorTest.java b/tests/uiautomator/src/com/android/uiautomator/cts/UiAutomatorTest.java
new file mode 100644
index 0000000..9873d1f
--- /dev/null
+++ b/tests/uiautomator/src/com/android/uiautomator/cts/UiAutomatorTest.java
@@ -0,0 +1,1072 @@
+/*
+ * 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.uiautomator.cts;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.uiautomator.core.UiCollection;
+import com.android.uiautomator.core.UiDevice;
+import com.android.uiautomator.core.UiObject;
+import com.android.uiautomator.core.UiObjectNotFoundException;
+import com.android.uiautomator.core.UiScrollable;
+import com.android.uiautomator.core.UiSelector;
+import com.android.uiautomator.core.UiWatcher;
+import com.android.uiautomator.testrunner.UiAutomatorTestCase;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Sanity test uiautomator functionality on target device.
+ */
+public class UiAutomatorTest extends UiAutomatorTestCase {
+    private static final String LOG_TAG = UiAutomatorTest.class.getSimpleName();
+    private static final String[] LIST_SCROLL_TESTS = new String[] {
+            "Test 17", "Test 11", "Test 20", "Test 35"
+    };
+    private static final String PKG_NAME = "com.android.uiautomator.app";
+    private static final String LAUNCH_APP = "am start -a android.intent.action.MAIN -n "
+            + PKG_NAME + "/.MainActivity -W";
+
+    // Maximum wait for key object to become visible
+    private static final int WAIT_EXIST_TIMEOUT = 5 * 1000;
+
+    private static final String SCREEN_SHOT_FILE_PATH_NAME = "/data/local/tmp/ctsScreenShot";
+
+    // Should match the value defined in UiObject
+    private static final int FINGER_TOUCH_HALF_WIDTH = 20;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Make sure the test app is always running
+        UiDevice.getInstance().waitForIdle();
+        if (!new UiObject(new UiSelector().packageName(PKG_NAME)).exists())
+            runShellCommand(LAUNCH_APP);
+    }
+
+    /**
+     * Helper to execute a command on the shell
+     *
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    private void runShellCommand(String command) throws IOException, InterruptedException {
+        Process p = null;
+        BufferedReader resultReader = null;
+        try {
+            p = Runtime.getRuntime().exec(command);
+            int status = p.waitFor();
+            if (status != 0) {
+                throw new RuntimeException(String.format("Run shell command: %s, status: %s",
+                        command, status));
+            }
+        } finally {
+            if (resultReader != null) {
+                resultReader.close();
+            }
+            if (p != null) {
+                p.destroy();
+            }
+        }
+    }
+
+    /*
+     * Items in the listScrollTests array should be spread out such that a
+     * scroll is required to reach each item at each of the far ends.
+     */
+    public void testListScrollAndSelect() throws UiObjectNotFoundException {
+        UiScrollable listView = new UiScrollable(
+                new UiSelector().className(android.widget.ListView.class.getName()));
+
+        // on single fragment display
+        if (!listView.exists())
+            UiDevice.getInstance().pressBack();
+
+        for (String test : LIST_SCROLL_TESTS) {
+            openTest(test);
+            verifyTestDetailsExists(test);
+        }
+    }
+
+    /**
+     * Test erasing of multi word text in edit field and input of new text. Test
+     * verifying input text using a complex UiSelector
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testTextEraseAndInput() throws UiObjectNotFoundException {
+        String testText = "Android Ui Automator Input Text";
+        openTest("Test 1");
+
+        UiObject editText = new UiObject(new UiSelector().className(android.widget.EditText.class
+                .getName()));
+        editText.setText(testText);
+
+        UiObject submitButton = new UiObject(new UiSelector()
+                .className(android.widget.Button.class.getName()).clickable(true)
+                .textStartsWith("Submit"));
+        submitButton.click();
+
+        UiObject result = new UiObject(new UiSelector().className(
+                android.widget.LinearLayout.class.getName()).childSelector(
+                (new UiSelector().className(android.widget.ScrollView.class.getName())
+                        .childSelector(new UiSelector().className(android.widget.TextView.class
+                                .getName())))));
+
+        if (!testText.equals(result.getText())) {
+            throw new UiObjectNotFoundException("Test text: " + testText);
+        }
+
+        getObjectByText("OK").click();
+    }
+
+    /**
+     * Select each of the buttons by using only the content description property
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectByContentDescription() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        getObjectByDescription("Button 1").click();
+        verifyDialogActionResults("Button 1");
+        getObjectByDescription("Button 2").click();
+        verifyDialogActionResults("Button 2");
+        getObjectByDescription("Button 3").click();
+        verifyDialogActionResults("Button 3");
+    }
+
+    /**
+     * Select each of the buttons by using only the text property
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectByText() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        getObjectByText("Button 1").click();
+        verifyDialogActionResults("Button 1");
+        getObjectByText("Button 2").click();
+        verifyDialogActionResults("Button 2");
+        getObjectByText("Button 3").click();
+        verifyDialogActionResults("Button 3");
+    }
+
+    /**
+     * Select each of the buttons by using only the index property
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectByIndex() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        getObjectByIndex(android.widget.Button.class.getName(), 0).click();
+        verifyDialogActionResults("Button 1");
+        getObjectByIndex(android.widget.Button.class.getName(), 1).click();
+        verifyDialogActionResults("Button 2");
+        getObjectByIndex(android.widget.Button.class.getName(), 2).click();
+        verifyDialogActionResults("Button 3");
+    }
+
+    /**
+     * Select each of the buttons by using only the instance number
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectByInstance() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        getObjectByInstance(android.widget.Button.class.getName(), 0).click();
+        verifyDialogActionResults("Button 1");
+        getObjectByInstance(android.widget.Button.class.getName(), 1).click();
+        verifyDialogActionResults("Button 2");
+        getObjectByInstance(android.widget.Button.class.getName(), 2).click();
+        verifyDialogActionResults("Button 3");
+    }
+
+    /**
+     * Test when a node's state is changed due to an action, it is updated in the accessibility
+     * hierarchy.
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectAfterContentChanged() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        UiObject dynaButton = getObjectByText("Before");
+        dynaButton.click();
+        assertTrue("Button state change is not refreshed in accessibility hierarchy",
+                getObjectByText("After").exists());
+    }
+
+    /**
+     * Test opening the options menu using the soft buttons
+     *
+     * @throws UiObjectNotFoundException
+     * @throws InterruptedException
+     * @throws IOException
+     */
+    public void testDeviceSoftKeys() throws UiObjectNotFoundException, IOException,
+            InterruptedException {
+        openTest("Test 2");
+        UiDevice device = UiDevice.getInstance();
+        device.pressMenu();
+        getObjectByText("Finish").click();
+        verifyDialogActionResults("Finish");
+
+        // Back button
+        openTest("Test 1");
+        UiObject editText = new UiObject(new UiSelector().className(android.widget.EditText.class
+                .getName()));
+        editText.setText("Android Geppetto Test Application");
+
+        UiObject submitButton = new UiObject(new UiSelector()
+                .className(android.widget.Button.class.getName()).clickable(true)
+                .textStartsWith("Submit"));
+        submitButton.click();
+
+        // Text from the popup dialog
+        UiObject result = new UiObject(new UiSelector().textContains("geppetto"));
+
+        // Back button test to dismiss the dialog
+        assertTrue("Wait for exist must return true", result.waitForExists(2000));
+        device.pressBack();
+        result.waitUntilGone(1000);
+        assertFalse("Wait for exist must return false after press back", result.exists());
+
+        // Home button test
+        openTest("Test 5");
+        String pkgName = device.getCurrentPackageName();
+        assertTrue("CTS test app must be running", pkgName.equals(PKG_NAME));
+        device.pressHome();
+        boolean gone = new UiObject(new UiSelector().packageName(PKG_NAME)).waitUntilGone(5000);
+        assertTrue("CTS test app still visble after pressing home", gone);
+    }
+
+    /**
+     * This view is in constant update generating window content changed events.
+     * The test will read the time displayed and exhaust each wait for idle
+     * timeout until it read and sets the text back into the edit field and
+     * presses submit. A dialog box should pop up with the time it took since
+     * reading the value until pressing submit.
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testWaitForIdleTimeout() throws UiObjectNotFoundException {
+        openTest("Test 3");
+        UiObject clk = new UiObject(new UiSelector().descriptionStartsWith("Performance "));
+
+        // First default wait for idle timeout assumed to be 10 seconds
+        String txtTime = clk.getText();
+        UiObject edit = new UiObject(new UiSelector().className(android.widget.EditText.class
+                .getName()));
+
+        // Second default wait for idle timeout assumed to be 10 seconds.
+        // Total ~20.
+        edit.setText(txtTime);
+
+        // Third default wait for idle timeout assumed to be 10 seconds.
+        // Total ~30.
+        getObjectByText("Submit").click();
+
+        // The value read should have value between 30 and 60 seconds indicating
+        // that the internal default timeouts for wait-for-idle is in acceptable
+        // range.
+        UiObject readTime = new UiObject(new UiSelector().className(
+                android.widget.TextView.class.getName()).instance(1));
+        String timeDiff = readTime.getText();
+        Log.i(LOG_TAG, "Sync time: " + timeDiff);
+
+        getObjectByText("OK").click();
+
+        int totalDelay = Integer.parseInt(timeDiff);
+
+        // Cumulative waits in this test should add up to at minimum 30 seconds
+        assertFalse("Timeout for wait-for-idle is too short. Expecting minimum 30 seconds",
+                totalDelay < 30 * 1000);
+
+        // allow for tolerance in time measurements due to differences between
+        // device speeds
+        assertFalse("Timeout for wait-for-idle is too long. Expecting maximum 60 seconds",
+                totalDelay > 60 * 1000);
+    }
+
+    /**
+     * This view is in constant update generating window content changed events.
+     * This test uses the soft key presses and clicks while the background
+     * screen is constantly updating causing a constant busy state.
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testVerifyMenuClicks() throws UiObjectNotFoundException {
+        openTest("Test 3");
+        UiDevice.getInstance().pressMenu();
+        new UiObject(new UiSelector().text("Submit")).click();
+        verifyDialogActionResults("Submit");
+        UiDevice.getInstance().pressMenu();
+        new UiObject(new UiSelector().text("Exit")).click();
+        verifyDialogActionResults("Exit");
+    }
+
+    /**
+     * Verifies swipeRight, swipeLeft and raw swipe APIs perform as expected.
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSwipes() throws UiObjectNotFoundException {
+        openTest("Test 4");
+        UiObject textView = new UiObject(new UiSelector().textContains("["));
+
+        textView.swipeLeft(10);
+        assertTrue("UiObject swipe left 1->2", "[ 2 ]".equals(textView.getText()));
+
+        textView.swipeLeft(10);
+        assertTrue("UiObject swipe left 2->3", "[ 3 ]".equals(textView.getText()));
+
+        textView.swipeLeft(10);
+        assertTrue("UiObject swipe left 3->4", "[ 4 ]".equals(textView.getText()));
+
+        textView.swipeRight(10);
+        assertTrue("UiObject swipe right 3<-4", "[ 3 ]".equals(textView.getText()));
+
+        textView.swipeRight(10);
+        assertTrue("UiObject swipe right 2<-3", "[ 2 ]".equals(textView.getText()));
+
+        textView.swipeRight(10);
+        assertTrue("UiObject swipe right 1<-2", "[ 1 ]".equals(textView.getText()));
+
+        Rect tb = textView.getBounds();
+        UiDevice.getInstance().swipe(tb.right - 20, tb.centerY(), tb.left + 20, tb.centerY(), 50);
+
+        SystemClock.sleep(100);
+        assertTrue("UiDevice raw swipe 1->2", "[ 2 ]".equals(textView.getText()));
+    }
+
+    /**
+     * Creates a complex selector
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testComplexSelectors() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiSelector frameLayout = new UiSelector().className(android.widget.FrameLayout.class
+                .getName());
+        UiSelector gridLayout = new UiSelector().className(android.widget.GridLayout.class
+                .getName());
+        UiSelector toggleButton = new UiSelector().className(android.widget.ToggleButton.class
+                .getName());
+        UiObject button = new UiObject(frameLayout.childSelector(gridLayout).childSelector(
+                toggleButton));
+
+        assertTrue("Toggle button value should be OFF", "OFF".equals(button.getText()));
+        button.click();
+        assertTrue("Toggle button value should be ON", "ON".equals(button.getText()));
+        button.click();
+        assertTrue("Toggle button value should be OFF", "OFF".equals(button.getText()));
+    }
+
+    /**
+     * Test when an object does not exist, an exception is thrown
+     * @throws UiObjectNotFoundException
+     */
+    public void testExceptionObjectNotFound() throws UiObjectNotFoundException {
+        UiSelector selector = new UiSelector().text("Nothing should be found");
+        UiSelector child = new UiSelector().className("Nothing");
+        UiObject obj = new UiObject(selector.childSelector(child));
+
+        assertFalse("Object is reported as existing", obj.exists());
+
+        try {
+            obj.click();
+        } catch (UiObjectNotFoundException e) {
+            return;
+        }
+        assertTrue("Exception not thrown for Object not found", false);
+    }
+
+    /**
+     * Verifies the UiWatcher registration and trigger function
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testUiWatcher() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiDevice device = UiDevice.getInstance();
+        device.registerWatcher("Artificial crash", new UiWatcher() {
+
+            @Override
+            public boolean checkForCondition() {
+                if (new UiObject(new UiSelector().packageName("android")).exists()) {
+                    try {
+                        // Expecting a localized OK button
+                        new UiObject(new UiSelector().className(
+                                android.widget.Button.class.getName()).enabled(true)).click();
+                    } catch (UiObjectNotFoundException e) {
+                    }
+                    return true;
+                }
+                return false;
+            }
+        });
+
+        // Causes a runtime exception to be thrown
+        getObjectByText("Button").click();
+
+        // Fake doing something while the exception is being displayed
+        SystemClock.sleep(2000);
+        device.runWatchers();
+        assertTrue("UiWatcher not triggered", device.hasAnyWatcherTriggered());
+    }
+
+    /**
+     * Verifies the 'checked' property of both UiSelector and UiObject
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectorChecked() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiObject checkboxChecked = new UiObject(new UiSelector().className(
+                android.widget.CheckBox.class.getName()).checked(true));
+        UiObject checkboxNotChecked = new UiObject(new UiSelector().className(
+                android.widget.CheckBox.class.getName()).checked(false));
+
+        checkboxNotChecked.click();
+        assertTrue("Checkbox should be checked", checkboxChecked.isChecked());
+        checkboxChecked.click();
+        assertFalse("Checkbox should be unchecked", checkboxNotChecked.isChecked());
+    }
+
+    /**
+     * Verifies the 'Clickable' property of both the UiSelector and UiObject
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectorClickable() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiSelector clickableCheckbox = new UiSelector().clickable(true).className(
+                android.widget.CheckBox.class.getName());
+        UiSelector notClickableProgress = new UiSelector().clickable(false).className(
+                android.widget.ProgressBar.class.getName());
+
+        assertTrue("Selector clickable", new UiObject(clickableCheckbox).isClickable());
+        assertFalse("Selector not clickable", new UiObject(notClickableProgress).isClickable());
+    }
+
+    /**
+     * Verifies the 'focusable' property of both UiSelector and UiObject
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectorFocusable() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiSelector mainLayout = new UiSelector().description("Widgets Collection");
+        UiSelector focusableCheckbox = mainLayout.childSelector(new UiSelector().className(
+                android.widget.CheckBox.class.getName()).focusable(true));
+        UiSelector notFocusableSpinner = mainLayout.childSelector(new UiSelector().className(
+                android.widget.Spinner.class.getName()).focusable(false));
+
+        assertTrue("Selector focusable", new UiObject(focusableCheckbox).isFocusable());
+        assertFalse("Selector not focusable", new UiObject(notFocusableSpinner).isFocusable());
+    }
+
+    /**
+     * Verifies the 'DescriptionContains' property of UiSelector
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectorDescriptionContains() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiSelector progressDescriptionContains = new UiSelector().descriptionContains("%");
+        assertTrue("Selector descriptionContains", "Progress is 50 %".equals(new UiObject(
+                progressDescriptionContains).getContentDescription()));
+    }
+
+    /**
+     * Verifies the 'DescriptionStarts' property of UiSelector
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectorDescriptionStarts() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiSelector progressDescriptionStart = new UiSelector().descriptionStartsWith("progress");
+        assertTrue("Selector descriptionStart", "Progress is 50 %".equals(new UiObject(
+                progressDescriptionStart).getContentDescription()));
+    }
+
+    /**
+     * Verifies the 'Enabled' property of both UiSelector and UiObject
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testSelectorEnabled() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiSelector mainLayout = new UiSelector().description("Widgets Collection");
+        UiSelector buttonDisabled = mainLayout.childSelector(new UiSelector().className(
+                android.widget.Button.class.getName()).enabled(false));
+        UiSelector buttonEnabled = mainLayout.childSelector(new UiSelector().className(
+                android.widget.Button.class.getName()).enabled(true));
+
+        assertFalse("Selector enabled false", new UiObject(buttonDisabled).isEnabled());
+        assertTrue("Selector enabled true", new UiObject(buttonEnabled).isEnabled());
+    }
+
+    /**
+     * Verifies the UiCollection object child counting by object pattern
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testCollectionCount() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiCollection collection = new UiCollection(
+                new UiSelector().description("Widgets Collection"));
+        assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
+
+        assertTrue("Collection count",
+                collection.getChildCount(new UiSelector().clickable(true)) == 6);
+    }
+
+    /**
+     * Verifies the UiCollection can find an object by text and returning by
+     * pattern
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testCollectionGetChildByText() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiCollection collection = new UiCollection(
+                new UiSelector().description("Widgets Collection"));
+        assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
+
+        UiObject item = collection.getChildByText(
+                new UiSelector().className(android.widget.Button.class.getName()), "Button");
+
+        assertTrue("Collection get child by text", "Button".equals(item.getText()));
+    }
+
+    /**
+     * Verifies the UiCollection can find an object by instance and returning by
+     * pattern
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testCollectionGetChildByInstance() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiCollection collection = new UiCollection(
+                new UiSelector().description("Widgets Collection"));
+        assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
+
+        // find the second button
+        UiObject item = collection.getChildByInstance(
+                new UiSelector().className(android.widget.Button.class.getName()), 1);
+
+        assertTrue("Collection get child by instance", "Button".equals(item.getText()));
+    }
+
+    /**
+     * Verifies the UiCollection can find an object by description and returning
+     * by pattern
+     *
+     * @throws UiObjectNotFoundException
+     */
+    public void testCollectionGetChildByDescription() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiCollection collection = new UiCollection(
+                new UiSelector().description("Widgets Collection"));
+        assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
+
+        UiObject item = collection.getChildByDescription(
+                new UiSelector().className(android.widget.Button.class.getName()),
+                "Description for Button");
+
+        assertTrue("Collection get child by description", "Button".equals(item.getText()));
+    }
+
+    /**
+     * Test Orientation APIs by causing rotations and verifying current state
+     *
+     * @throws RemoteException
+     * @throws UiObjectNotFoundException
+     * @since API Level 17
+     */
+    public void testRotation() throws RemoteException, UiObjectNotFoundException {
+        openTest("Test 5");
+        UiDevice device = UiDevice.getInstance();
+
+        device.setOrientationLeft();
+        device.waitForIdle(); // isNaturalOrientation is not waiting for idle
+        SystemClock.sleep(1000);
+        assertFalse("Device orientation should not be natural", device.isNaturalOrientation());
+
+        device.setOrientationNatural();
+        device.waitForIdle(); // isNaturalOrientation is not waiting for idle
+        SystemClock.sleep(1000);
+        assertTrue("Device orientation should be natural", device.isNaturalOrientation());
+
+        device.setOrientationRight();
+        device.waitForIdle(); // isNaturalOrientation is not waiting for idle
+        SystemClock.sleep(1000);
+        assertFalse("Device orientation should not be natural", device.isNaturalOrientation());
+
+        device.setOrientationNatural();
+    }
+
+    /**
+     * Reads the current device's product name. Since it is not possible to predetermine the
+     * would be value, the check verifies that the value is not null and not empty.
+     *
+     * @since API Level 17
+     */
+    public void testGetProductName() {
+        String name = UiDevice.getInstance().getProductName();
+        assertFalse("Product name check returned empty string", name.isEmpty());
+    }
+
+    /**
+     * Select each of the buttons by using only regex text
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 17
+     */
+    public void testSelectByTextMatch() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        getObjectByTextMatch(".*n\\s1$").click();
+        verifyDialogActionResults("Button 1");
+        getObjectByTextMatch(".*n\\s2$").click();
+        verifyDialogActionResults("Button 2");
+        getObjectByTextMatch(".*n\\s3$").click();
+        verifyDialogActionResults("Button 3");
+    }
+
+    /**
+     * Select each of the buttons by using only regex content-description
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 17
+     */
+    public void testSelectByDescriptionMatch() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        getObjectByDescriptionMatch(".*n\\s1$").click();
+        verifyDialogActionResults("Button 1");
+        getObjectByDescriptionMatch(".*n\\s2$").click();
+        verifyDialogActionResults("Button 2");
+        getObjectByDescriptionMatch(".*n\\s3$").click();
+        verifyDialogActionResults("Button 3");
+    }
+
+    /**
+     * Select each of the buttons by using only regex class name
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 17
+     */
+    public void testSelectByClassMatch() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiObject tgl = getObjectByClassMatch(".*ToggleButton$", 0);
+        String tglValue = tgl.getText();
+        tgl.click();
+
+        assertFalse("Matching class by Regex failed", tglValue.equals(tgl.getText()));
+    }
+
+    /**
+     * Select each of the buttons by using only class type
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 17
+     */
+    public void testSelectByClassType() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiObject tgl = getObjectByClass(android.widget.ToggleButton.class, 0);
+        String tglValue = tgl.getText();
+        tgl.click();
+
+        assertFalse("Matching class by class type failed", tglValue.equals(tgl.getText()));
+    }
+
+    /**
+     * Test the coordinates of 3 buttons side by side verifying vertical and
+     * horizontal coordinates.
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 17
+     */
+    public void testGetVisibleBounds() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        Rect rect1 = getObjectByText("Button 1").getVisibleBounds();
+        Rect rect2 = getObjectByText("Button 2").getVisibleBounds();
+        Rect rect3 = getObjectByText("Button 3").getVisibleBounds();
+
+        assertTrue("X coordinate check failed",
+                rect1.left < rect2.left && rect2.right < rect3.right);
+        assertTrue("Y coordinate check failed",
+                rect1.top == rect2.top && rect2.bottom == rect3.bottom);
+    }
+
+   /**
+     * Tests the LongClick functionality in the API
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 17
+     */
+    public void testSelectorLongClickable() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        getObjectByText("Button 1").longClick();
+        verifyDialogActionResults("Longclick Button 1");
+    }
+
+    /**
+     * Test the UiSelector's long-clickable property
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 17
+     */
+    public void testSelectorLongClickableProperty() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        UiObject button3 = new UiObject(new UiSelector().className(
+                android.widget.Button.class).longClickable(true).instance(2));
+        button3.longClick();
+        verifyDialogActionResults("Longclick Button 3");
+    }
+
+    /**
+     * Takes a screen shot of the current display and checks if the file is
+     * created and is not zero size.
+     *
+     * @since API Level 17
+     */
+    public void testTakeScreenShots() {
+        File storePath = new File(SCREEN_SHOT_FILE_PATH_NAME);
+        getUiDevice().takeScreenshot(storePath);
+
+        assertTrue("Screenshot file not detected in store", storePath.exists());
+        assertTrue("Zero size for screenshot file", storePath.length() > 0);
+    }
+
+    /**
+     * Verifies the 'Resource-Id' property of UiSelector
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 18
+     */
+    public void testSelectorResourceId() throws UiObjectNotFoundException {
+        openTest("Test 5");
+        UiSelector toggleSelector =
+                new UiSelector().resourceId("com.android.uiautomator.app:id/test_5_toggleButton");
+        UiObject toggleButton = new UiObject(toggleSelector);
+        assertTrue("Object with selector resource-id not found", toggleButton.exists());
+        assertTrue("Incorrect object for selector resource-id returned",
+                "OFF".equals(toggleButton.getText()) || "ON".equals(toggleButton.getText()));
+    }
+
+    /**
+     * Verify the UiSelector property resourceIdMatches
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 18
+     */
+    public void testSelectorResourceIdMatches() throws UiObjectNotFoundException {
+        openTest("Test 2");
+        new UiObject(new UiSelector().resourceIdMatches("(?i).*button.*").instance(2)).click();
+        verifyDialogActionResults("Button 3");
+        new UiObject(new UiSelector().resourceIdMatches("(?i).*button1.*")).click();
+        verifyDialogActionResults("Button 1");
+    }
+
+    /**
+     * Performs a pinch out from the center of a view to its edges and listens to
+     * the motion events to make sure the starting and ending points of both pointers
+     * are correct.
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 18
+     */
+    public void testPinchOut() throws UiObjectNotFoundException {
+        openTest("Test 12");
+
+        UiObject screen = new UiObject(
+                new UiSelector().description("Details View"));
+
+        // get the current view dimensions
+        Rect screenRect = screen.getBounds();
+
+        // perform the pinch for 100% of the view dimensions starting form
+        // the center out to the edges.
+        screen.pinchOut(100, 30);
+
+        // dialog with the detected pointers motion coordinates is displayed.
+        UiObject results = new UiObject(new UiSelector().className(
+                android.widget.ScrollView.class).childSelector(new UiSelector().className(
+                        android.widget.TextView.class)));
+        String allPointers = results.getText();
+        new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
+
+        // parse pointer 1
+        Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
+        Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
+        // parse pointer 2
+        Point p2s = parsePointerCoordinates(allPointers, 1, 0); // start
+        Point p2e = parsePointerCoordinates(allPointers, 1, 1); // end
+
+        assertTrue("All Y axis coordinates for pointer 1 must be the same", p1s.y == p1e.y);
+        assertTrue("All Y axis coordinates for pointer 2 must be the same", p2s.y == p2e.y);
+        assertTrue("All Y axis coordinates for both pointers must be the same", p1s.y == p2s.y);
+        assertTrue("Pinch must be in center of target view", p2s.y == screenRect.centerY());
+
+        assertTrue("Touch-down X coordinate for pointer 1 is invalid",
+                withinMarginOfError(0.125f, screenRect.centerX(), p1s.x));
+
+        assertTrue("Touch-down X coordinate for pointer 2 is invalid",
+                withinMarginOfError(0.125f, screenRect.centerX(), p2s.x));
+
+        assertTrue("Touch-up X coordinate for pointer 1 is invalid",
+                withinMarginOfError(0.125f, screenRect.centerX() - screenRect.left,
+                        screenRect.centerX() - p1e.x));
+
+        assertTrue("Touch-up X coordinate for pointer 2 is invalid",
+                withinMarginOfError(0.125f, screenRect.right, p2e.x));
+    }
+
+    /**
+     * Performs a pinch in from the edges of a view to its center and listens to
+     * the motion events to make sure the starting and ending points of both pointers
+     * are correct.
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 18
+     */
+    public void testPinchIn() throws UiObjectNotFoundException {
+        openTest("Test 12");
+
+        UiObject screen = new UiObject(
+                new UiSelector().description("Details View"));
+
+        // get the current view dimensions
+        Rect screenRect = screen.getBounds();
+
+        // perform the pinch for 100% of the view dimensions starting form
+        // the edges in towards the center.
+        screen.pinchIn(100, 30);
+
+        // dialog with the detected pointers motion coordinates is displayed.
+        UiObject results = new UiObject(new UiSelector().className(
+                android.widget.ScrollView.class).childSelector(new UiSelector().className(
+                        android.widget.TextView.class)));
+        String allPointers = results.getText();
+        new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
+
+        // parse pointer 1
+        Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
+        Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
+        // parse pointer 2
+        Point p2s = parsePointerCoordinates(allPointers, 1, 0); // start
+        Point p2e = parsePointerCoordinates(allPointers, 1, 1); // end
+
+        assertTrue("All Y axis coordinates for pointer 1 must be the same", p1s.y == p1e.y);
+        assertTrue("All Y axis coordinates for pointer 2 must be the same", p2s.y == p2e.y);
+        assertTrue("All Y axis coordinates for both pointers must be the same", p1s.y == p2s.y);
+        assertTrue("Pinch must be in center of target view", p2s.y == screenRect.centerY());
+
+        assertTrue("Touch-down X coordinate for pointer 1 is invalid",
+                withinMarginOfError(0.125f, screenRect.centerX() - screenRect.left,
+                        screenRect.centerX() -  p1s.x));
+
+        assertTrue("Touch-down X coordinate for pointer 2 is invalid",
+                withinMarginOfError(0.125f, screenRect.right, p2s.x));
+
+        assertTrue("Touch-up X coordinate for pointer 1 is invalid",
+                withinMarginOfError(0.125f, screenRect.centerX() - FINGER_TOUCH_HALF_WIDTH, p1e.x));
+
+        assertTrue("Touch-up X coordinate for pointer 2 is invalid",
+                withinMarginOfError(0.125f, screenRect.centerX() + FINGER_TOUCH_HALF_WIDTH, p2e.x));
+    }
+
+    /**
+     * Performs a drag and drop operation from one UiObject to another UiObject
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 18
+     */
+    public void testDragToObject() throws UiObjectNotFoundException {
+        openTest("Test 5");
+
+        UiObject imageButton = new UiObject(new UiSelector().description("Image button"));
+        UiObject starsBar = new UiObject(new UiSelector().className(android.widget.RatingBar.class));
+
+        Rect starsBarRect = starsBar.getBounds();
+        Rect imageButtonRect = imageButton.getBounds();
+        imageButton.dragTo(starsBar, 30);
+
+        // dialog with the detected pointers motion coordinates is displayed.
+        UiObject results = new UiObject(new UiSelector().className(
+                android.widget.ScrollView.class).childSelector(new UiSelector().className(
+                        android.widget.TextView.class)));
+        String allPointers = results.getText();
+        new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
+
+        // parse pointer 1
+        Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
+        Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
+
+        assertTrue("Invalid touch starting.X reported",
+                withinMarginOfError(0.05f, imageButtonRect.centerX(), p1s.x));
+        assertTrue("Invalid touch starting.Y reported",
+                withinMarginOfError(0.05f, imageButtonRect.centerY(), p1s.y));
+        assertTrue("Invalid touch ending.X reported",
+                withinMarginOfError(0.05f, starsBarRect.centerX(), p1e.x));
+        assertTrue("Invalid touch ending.Y reported",
+                withinMarginOfError(0.05f, starsBarRect.centerY(), p1e.y));
+    }
+
+    /**
+     * Performs a drag and drop operation from one UiObject to a specified coordinates
+     *
+     * @throws UiObjectNotFoundException
+     * @since API Level 18
+     */
+   public void testDragToCoordinates() throws UiObjectNotFoundException {
+       openTest("Test 5");
+
+       UiObject imageButton = new UiObject(new UiSelector().description("Image button"));
+       UiObject starsBar = new UiObject(new UiSelector().className(android.widget.RatingBar.class));
+
+       Rect starsBarRect = starsBar.getBounds();
+       Rect imageButtonRect = imageButton.getBounds();
+       imageButton.dragTo(starsBarRect.centerX(), starsBarRect.centerY(), 30);
+
+       // dialog with the detected pointers motion coordinates is displayed.
+       UiObject results = new UiObject(new UiSelector().className(
+               android.widget.ScrollView.class).childSelector(new UiSelector().className(
+                       android.widget.TextView.class)));
+       String allPointers = results.getText();
+       new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
+
+       // parse pointer 1
+       Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
+       Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
+
+       assertTrue("Invalid touch starting.X reported",
+               withinMarginOfError(0.05f, imageButtonRect.centerX(), p1s.x));
+       assertTrue("Invalid touch starting.Y reported",
+               withinMarginOfError(0.05f, imageButtonRect.centerY(), p1s.y));
+       assertTrue("Invalid touch ending.X reported",
+               withinMarginOfError(0.05f, starsBarRect.centerX(), p1e.x));
+       assertTrue("Invalid touch ending.Y reported",
+               withinMarginOfError(0.05f, starsBarRect.centerY(), p1e.y));
+   }
+
+   /**
+    * Detect if actual value is within the allowable margin of error of the expected value.
+    *
+    * Used essentially with actual values that may vary from the expected values such in the
+    * cases of touch and pinch and touch and swipe where the starting or ending points may
+    * not exactly match the expected value.
+    *
+    * @param marginPrecent is values between 0 and 1
+    * @param expected
+    * @param actual
+    * @return true if actual is within the allowed range from expected
+    */
+   private boolean withinMarginOfError(float marginPrecent, int expected, int actual) {
+       int m = (int) (marginPrecent * expected);
+       return actual >= expected - m && actual <= expected + m;
+   }
+
+   /**
+     * Parses a string containing starting to ending coordinates of one or more pointers.
+     *
+     * @param allPointers is a raw string with coordinates from all detected pointers
+     * @param pointerNumber is the desired pointer to be parsed
+     * @param edge is the 0 for the start or 1 for the end of the swipe
+     * @return Point containing the start or end coordinates of the specified pointer number
+     */
+    private Point parsePointerCoordinates(String allPointers, int pointerNumber, int edge) {
+        String pointers[] = allPointers.split("\n");
+        String coordinates = pointers[pointerNumber].split(":")[edge];
+        String xy[] = coordinates.split(",");
+        return new Point(Integer.parseInt(xy[0]), Integer.parseInt(xy[1]));
+    }
+
+    /**
+     * Private helper to open test views. Also covers UiScrollable tests
+     *
+     * @param name
+     * @throws UiObjectNotFoundException
+     */
+    private void openTest(String name) throws UiObjectNotFoundException {
+        try {
+            UiDevice.getInstance().setOrientationNatural();
+        } catch (RemoteException e) {
+            // will catch it in its own test. For now try to put the device
+            // in its natural orientation prior to each test
+        }
+        UiScrollable listView = new UiScrollable(
+                new UiSelector().className(android.widget.ListView.class.getName()));
+
+        // on single fragment display
+        if (!listView.exists())
+            UiDevice.getInstance().pressBack();
+
+        UiObject testItem = listView.getChildByText(
+                new UiSelector().className(android.widget.TextView.class.getName()), name);
+
+        testItem.click();
+    }
+
+    private void verifyTestDetailsExists(String name) throws UiObjectNotFoundException {
+        // verify that we're at the right test
+        new UiObject(new UiSelector().description("Details").text(name)).getText();
+    }
+
+    private UiObject getObjectByText(String txt) {
+        return new UiObject(new UiSelector().text(txt));
+    }
+
+    private UiObject getObjectByTextMatch(String regex) {
+        return new UiObject(new UiSelector().textMatches(regex));
+    }
+
+    private UiObject getObjectByDescriptionMatch(String regex) {
+        return new UiObject(new UiSelector().descriptionMatches(regex));
+    }
+
+    private UiObject getObjectByDescription(String txt) {
+        return new UiObject(new UiSelector().description(txt));
+    }
+
+    private UiObject getObjectByClassMatch(String regex, int instance) {
+        return new UiObject(new UiSelector().classNameMatches(regex).instance(instance));
+    }
+
+    private <T> UiObject getObjectByClass(Class<T> type, int instance) {
+        return new UiObject(new UiSelector().className(type).instance(instance));
+    }
+
+    private UiObject getObjectByIndex(String className, int index) {
+        return new UiObject(new UiSelector().className(className).index(index));
+    }
+
+    private UiObject getObjectByInstance(String className, int instance) {
+        return new UiObject(new UiSelector().className(className).instance(instance));
+    }
+
+    private void verifyDialogActionResults(String txt) throws UiObjectNotFoundException {
+        if (!getObjectByText("Action results").exists() || !getObjectByText(txt).exists()) {
+            throw new UiObjectNotFoundException(txt);
+        }
+        getObjectByText("OK").click();
+    }
+}
diff --git a/tests/uiautomator/test-apps/Android.mk b/tests/uiautomator/test-apps/Android.mk
deleted file mode 100644
index e790e1e..0000000
--- a/tests/uiautomator/test-apps/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# 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.
-
-include $(call all-subdir-makefiles)
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk b/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk
deleted file mode 100644
index 3827754..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := CtsUiAutomatorApp
-LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/AndroidManifest.xml b/tests/uiautomator/test-apps/CtsUiAutomatorApp/AndroidManifest.xml
deleted file mode 100644
index 87c2d82..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/AndroidManifest.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.uiautomator"
-    android:versionCode="1"
-    android:versionName="1.0" >
-    <uses-sdk
-        android:minSdkVersion="14"
-        android:targetSdkVersion="15" />
-
-    <uses-permission android:name="android.permission.INTERNET"/>
-    <application
-        android:icon="@drawable/ic_launcher"
-        android:label="@string/app_name"
-        android:theme="@style/AppTheme" >
-        <activity
-            android:name=".MainActivity"
-            android:label="@string/title_test_list" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <activity
-            android:name=".SinglePaneDetailActivity"
-            android:label="@string/title_test_detail" >
-            <meta-data
-                android:name="android.support.PARENT_ACTIVITY"
-                android:value="FragmentActivity" />
-        </activity>
-     </application>
-
-</manifest>
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/list_activity.xml b/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/list_activity.xml
deleted file mode 100644
index 25bca5d..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/list_activity.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?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.
- -->
-<fragment xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:name="com.android.cts.uiautomator.TestListFragment"
-    android:id="@+id/item_list"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_marginLeft="16dp"
-    android:layout_marginRight="16dp"
-    tools:context=".MainActivity" />
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/twopane_activity.xml b/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/twopane_activity.xml
deleted file mode 100644
index 3777db6..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/res/layout/twopane_activity.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?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"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_marginLeft="16dp"
-    android:layout_marginRight="16dp"
-    android:divider="?android:attr/dividerHorizontal"
-    android:showDividers="middle"
-    tools:context=".TestListActivity">
-
-    <fragment
-        android:id="@+id/item_list"
-        android:name="com.android.cts.uiautomator.TestListFragment"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1" />
-
-    <FrameLayout android:id="@+id/test_detail_container"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="3" />
-
-</LinearLayout>
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/MainActivity.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/MainActivity.java
deleted file mode 100644
index 81833b7..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/MainActivity.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.view.WindowManager;
-
-public class MainActivity extends FragmentActivity implements TestListFragment.Callbacks {
-
-    private boolean mTwoPane;
-    public static final String LOG_TAG = "UiAutomatorApp";
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        // If the device is locked, this attempts to dismiss the KeyGuard
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
-                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
-                      WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
-        setContentView(R.layout.list_activity);
-
-        if (findViewById(R.id.test_detail_container) != null) {
-            mTwoPane = true;
-            ((TestListFragment) getSupportFragmentManager().findFragmentById(R.id.item_list))
-                    .setActivateOnItemClick(true);
-        }
-    }
-
-    @Override
-    public void onItemSelected(String id) {
-        if (mTwoPane) {
-            Fragment fragment = TestItems.getFragment(id);
-            getSupportFragmentManager().beginTransaction()
-                    .replace(R.id.test_detail_container, fragment).commit();
-        } else {
-            Intent detailIntent = new Intent(this, SinglePaneDetailActivity.class);
-            detailIntent.putExtra("item_id", id);
-            startActivity(detailIntent);
-        }
-    }
-}
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/SinglePaneDetailActivity.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/SinglePaneDetailActivity.java
deleted file mode 100644
index 1c0ff8c..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/SinglePaneDetailActivity.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.NavUtils;
-import android.view.Menu;
-import android.view.MenuItem;
-
-public class SinglePaneDetailActivity extends FragmentActivity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.singlepane_activity);
-        getActionBar().setDisplayHomeAsUpEnabled(true);
-
-        if (savedInstanceState == null) {
-            Fragment fragment = TestItems.getFragment(getIntent().getStringExtra("item_id"));
-            getSupportFragmentManager().beginTransaction()
-                    .add(R.id.test_results_detail_container, fragment).commit();
-        }
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        getMenuInflater().inflate(R.menu.test_results_detail_activity, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case android.R.id.home:
-                NavUtils.navigateUpFromSameTask(this);
-                return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-}
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test1DetailFragment.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test1DetailFragment.java
deleted file mode 100644
index e8eddba..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test1DetailFragment.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.Button;
-import android.widget.EditText;
-
-public class Test1DetailFragment extends Fragment {
-
-    public static final String ARG_ITEM_ID = "item_id";
-    private Button mSubmitButton;
-    private EditText mEditText;
-    TestItems.TestItem mItem;
-
-    public Test1DetailFragment() {
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        if (getArguments().containsKey(ARG_ITEM_ID)) {
-            mItem = TestItems.getTest(getArguments().getString(ARG_ITEM_ID));
-        }
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
-        View rootView = inflater.inflate(R.layout.test1_detail_fragment, container, false);
-        if (mItem != null) {
-            ((EditText) rootView.findViewById(R.id.test1TextField)).setText(mItem.mName);
-
-            mSubmitButton = (Button) rootView.findViewById(R.id.test1SubmitButton);
-            mEditText = (EditText) rootView.findViewById(R.id.test1TextField);
-            mEditText.setText("");
-            mSubmitButton.setOnClickListener(new Button.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    final String savedInput = mEditText.getText().toString();
-                    // clear so we won't be confused by the input text in
-                    // validation
-                    mEditText.setText("");
-                    // close soft keyboard
-                    InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
-                            Context.INPUT_METHOD_SERVICE);
-                    imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
-                    // display the submitted text
-                    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-                    builder.setTitle(R.string.item1_dialog_title);
-                    builder.setPositiveButton(R.string.OK, null);
-                    builder.setMessage(savedInput);
-                    AlertDialog diag = builder.create();
-                    diag.show();
-                }
-            });
-        }
-        return rootView;
-    }
-}
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test2DetailFragment.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test2DetailFragment.java
deleted file mode 100644
index 4fb322f..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test2DetailFragment.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.app.AlertDialog;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-
-public class Test2DetailFragment extends Fragment {
-    public static final String ARG_ITEM_ID = "item_id";
-    private Button mButton1, mButton2, mButton3, mDynaButton;
-
-    public Test2DetailFragment() {
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setHasOptionsMenu(true);
-    }
-
-    @Override
-    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        inflater.inflate(R.menu.test2_detail_activity, menu);
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-        builder.setTitle(R.string.dialog_title_result);
-        builder.setMessage(item.getTitle());
-        builder.setPositiveButton(R.string.OK, null);
-        AlertDialog diag = builder.create();
-        diag.show();
-        return super.onOptionsItemSelected(item);
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
-        View rootView = inflater.inflate(R.layout.test2_detail_fragment, container, false);
-
-        mButton1 = (Button) rootView.findViewById(R.id.test2button1);
-        mButton2 = (Button) rootView.findViewById(R.id.test2button2);
-        mButton3 = (Button) rootView.findViewById(R.id.test2button3);
-        mDynaButton = (Button) rootView.findViewById(R.id.test2dynaButton);
-
-        mButton1.setOnClickListener(new Button.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-                builder.setTitle(R.string.dialog_title_result);
-                builder.setPositiveButton(R.string.OK, null);
-                builder.setMessage(R.string.button1);
-                AlertDialog diag = builder.create();
-                diag.show();
-            }
-        });
-
-        mButton1.setOnLongClickListener(new Button.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-                builder.setTitle(R.string.dialog_title_result);
-                builder.setPositiveButton(R.string.OK, null);
-                builder.setMessage(R.string.button1long);
-                AlertDialog diag = builder.create();
-                diag.show();
-                return true;
-            }
-        });
-
-        mButton2.setOnClickListener(new Button.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-                builder.setTitle(R.string.dialog_title_result);
-                builder.setPositiveButton(R.string.OK, null);
-                builder.setMessage(R.string.button2);
-                AlertDialog diag = builder.create();
-                diag.show();
-            }
-        });
-
-        mButton2.setOnLongClickListener(new Button.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-                builder.setTitle(R.string.dialog_title_result);
-                builder.setPositiveButton(R.string.OK, null);
-                builder.setMessage(R.string.button2long);
-                AlertDialog diag = builder.create();
-                diag.show();
-                return true;
-            }
-        });
-
-        mButton3.setOnClickListener(new Button.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-                builder.setTitle(R.string.dialog_title_result);
-                builder.setPositiveButton(R.string.OK, null);
-                builder.setMessage(R.string.button3);
-                AlertDialog diag = builder.create();
-                diag.show();
-            }
-        });
-
-        mButton3.setOnLongClickListener(new Button.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-                builder.setTitle(R.string.dialog_title_result);
-                builder.setPositiveButton(R.string.OK, null);
-                builder.setMessage(R.string.button3long);
-                AlertDialog diag = builder.create();
-                diag.show();
-                return true;
-            }
-        });
-
-        mDynaButton.setOnClickListener(new Button.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mDynaButton.setText(R.string.buttonAfter);
-                mDynaButton.setContentDescription(getString(R.string.buttonAfter));
-            }
-        });
-
-        return rootView;
-    }
-}
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test3DetailFragment.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test3DetailFragment.java
deleted file mode 100644
index e0be0cf..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test3DetailFragment.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
-
-public class Test3DetailFragment extends Fragment {
-
-    public static final String ARG_ITEM_ID = "item_id";
-    private TextView mTextClock;
-    private Button mSubmitButton;
-    private EditText mEditText;
-    private long mCurrentTime;
-    private final Object sync = new Object();
-    private boolean mRunCounter = true;
-
-    public Test3DetailFragment() {
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setHasOptionsMenu(true);
-    }
-
-    @Override
-    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        inflater.inflate(R.menu.test2_detail_activity, menu);
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-        builder.setTitle(R.string.dialog_title_result);
-        builder.setMessage(item.getTitle());
-        builder.setPositiveButton(R.string.OK, null);
-        AlertDialog diag = builder.create();
-        diag.show();
-        return super.onOptionsItemSelected(item);
-    }
-
-    private final Handler mHandler = new Handler();
-
-    final Runnable mClockRunnable = new Runnable() {
-        @Override
-        public void run() {
-            // call the activity method that updates the UI
-            updateClockOnUi();
-        }
-    };
-
-    private void updateClockOnUi() {
-        synchronized (sync) {
-            mTextClock.setText("" + mCurrentTime);
-        }
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
-        View rootView = inflater.inflate(R.layout.test3_detail_fragment, container, false);
-        mTextClock = (TextView) rootView.findViewById(R.id.test3ClockTextView);
-        mSubmitButton = (Button) rootView.findViewById(R.id.test3SubmitButton);
-        mEditText = (EditText) rootView.findViewById(R.id.test3TextField);
-        mSubmitButton.setOnClickListener(new Button.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                // close soft keyboard
-                InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
-                        Context.INPUT_METHOD_SERVICE);
-                imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
-
-                // display the submitted text
-                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-                builder.setTitle(R.string.test3_dialog_title);
-                builder.setPositiveButton(R.string.OK, null);
-                CharSequence inputText = mEditText.getText();
-                if (inputText != null && !inputText.toString().isEmpty()) {
-                    long inputTime = Long.parseLong(inputText.toString());
-                    builder.setMessage("" + (mCurrentTime - inputTime));
-                } else {
-                    builder.setMessage("<NO DATA>");
-                }
-                AlertDialog diag = builder.create();
-                diag.show();
-                mEditText.setText("");
-                mRunCounter = false;
-            }
-        });
-
-        new Thread(new Runnable() {
-            @Override
-            public void run() {
-                while (mRunCounter) {
-                    synchronized (sync) {
-                        mCurrentTime = SystemClock.elapsedRealtime();
-                    }
-                    mHandler.post(mClockRunnable);
-                    SystemClock.sleep(100);
-                }
-            }
-        }).start();
-
-        return rootView;
-    }
-}
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test4DetailFragment.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test4DetailFragment.java
deleted file mode 100644
index 0c914dc..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test4DetailFragment.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.app.ActionBar;
-import android.app.FragmentTransaction;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-public class Test4DetailFragment extends Fragment implements ActionBar.TabListener {
-    public static final String ARG_ITEM_ID = "item_id";
-
-    /**
-     * The {@link android.support.v4.view.PagerAdapter} that will provide
-     * fragments for each of the sections. We use a
-     * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
-     * will keep every loaded fragment in memory. If this becomes too memory
-     * intensive, it may be best to switch to a
-     * {@link android.support.v4.app.FragmentStatePagerAdapter}.
-     */
-    SectionsPagerAdapter mSectionsPagerAdapter;
-
-    /**
-     * The {@link ViewPager} that will host the section contents.
-     */
-    ViewPager mViewPager;
-
-    public Test4DetailFragment() {
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
-    public void onDestroyView() {
-        getActivity().getActionBar().removeAllTabs();
-        super.onDestroyView();
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
-
-        View rootView = inflater.inflate(R.layout.test4_detail_fragment, container, false);
-
-        // Set up the action bar.
-        final ActionBar actionBar = getActivity().getActionBar();
-        if (actionBar.getTabCount() > 0) {
-            return rootView;
-        }
-        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-
-        // Create the adapter that will return a fragment for each of the three
-        // primary sections of the app.
-        mSectionsPagerAdapter = new SectionsPagerAdapter(getActivity().getSupportFragmentManager());
-
-        // Set up the ViewPager with the sections adapter.
-        mViewPager = (ViewPager) rootView.findViewById(R.id.test_4_detail_container);
-        mViewPager.setAdapter(mSectionsPagerAdapter);
-
-        // When swiping between different sections, select the corresponding
-        // tab. We can also use ActionBar.Tab#select() to do this if we have a
-        // reference to the Tab.
-        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
-            @Override
-            public void onPageSelected(int position) {
-                actionBar.setSelectedNavigationItem(position);
-            }
-        });
-
-        // For each of the sections in the app, add a tab to the action bar.
-        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
-            // Create a tab with text corresponding to the page title defined by
-            // the adapter. Also specify this Activity object, which implements
-            // the TabListener interface, as the listener for when this tab is
-            // selected.
-            actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i))
-                    .setTabListener(this));
-        }
-        return rootView;
-    }
-
-    @Override
-    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
-    }
-
-    @Override
-    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
-    }
-
-    @Override
-    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
-    }
-
-    /**
-     * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
-     * one of the primary sections of the app.
-     */
-    public class SectionsPagerAdapter extends FragmentPagerAdapter {
-
-        public SectionsPagerAdapter(FragmentManager fm) {
-            super(fm);
-        }
-
-        @Override
-        public Fragment getItem(int i) {
-            Fragment fragment = new DummySectionFragment();
-            Bundle args = new Bundle();
-            args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1);
-            fragment.setArguments(args);
-            return fragment;
-        }
-
-        @Override
-        public int getCount() {
-            return 4;
-        }
-
-        @Override
-        public CharSequence getPageTitle(int position) {
-            switch (position) {
-                case 0:
-                    return getString(R.string.title_section1).toUpperCase();
-                case 1:
-                    return getString(R.string.title_section2).toUpperCase();
-                case 2:
-                    return getString(R.string.title_section3).toUpperCase();
-                case 3:
-                    return getString(R.string.title_section4).toUpperCase();
-            }
-            return null;
-        }
-    }
-
-    /**
-     * A dummy fragment representing a section of the app, but that simply
-     * displays dummy text.
-     */
-    public static class DummySectionFragment extends Fragment {
-        public DummySectionFragment() {
-        }
-
-        public static final String ARG_SECTION_NUMBER = "section_number";
-
-        @Override
-        public View onCreateView(LayoutInflater inflater, ViewGroup container,
-                Bundle savedInstanceState) {
-            TextView textView = new TextView(getActivity());
-            textView.setGravity(Gravity.CENTER);
-            Bundle args = getArguments();
-            textView.setText("[ " + Integer.toString(args.getInt(ARG_SECTION_NUMBER)) + " ]");
-            return textView;
-        }
-    }
-}
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test5DetailFragment.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test5DetailFragment.java
deleted file mode 100644
index e2dd156..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test5DetailFragment.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.app.AlertDialog;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.ImageButton;
-import android.widget.SeekBar;
-import android.widget.Spinner;
-
-public class Test5DetailFragment extends Fragment {
-
-    public static final String ARG_ITEM_ID = "item_id";
-
-    class PointerEvent {
-        int startX;
-        int startY;
-        int endX;
-        int endY;
-    }
-
-    private final PointerEvent mPointerEvent = new PointerEvent();
-
-    public Test5DetailFragment() {
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
-        View rootView = inflater.inflate(R.layout.test5_detail_fragment, container, false);
-
-        // Set the content description for the following
-        Spinner spinner = (Spinner) rootView.findViewById(R.id.test_5_spinner);
-        spinner.setContentDescription("Spinner");
-        ImageButton imageButton = (ImageButton) rootView.findViewById(R.id.test_5_imageButton);
-        imageButton.setContentDescription("Image button");
-
-        // Each time this view is displayed, reset the following states
-        SeekBar seekBar = (SeekBar) rootView.findViewById(R.id.test_5_seekBar);
-        seekBar.setProgress(50);
-        seekBar.setContentDescription("Progress is 50 %");
-        CheckBox checkbox = (CheckBox) rootView.findViewById(R.id.test_5_checkBox);
-        checkbox.setChecked(false);
-
-        // Register click event handlers for the following
-        Button button = (Button) rootView.findViewById(R.id.test_5_button1);
-        button.setOnClickListener(new Button.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                // we want an artificial crash
-                throw new RuntimeException("Artificial crash to test UiWatcher");
-            }
-        });
-
-        imageButton.setOnTouchListener(new ImageButton.OnTouchListener() {
-
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                    resetTouchResults();
-                    collectStartAction(event, v);
-                } else if (event.getAction() == MotionEvent.ACTION_UP) {
-                    collectEndAction(event, v);
-                    displayTouchResults();
-                }
-                return false;
-            }
-        });
-
-        return rootView;
-    }
-
-    private void displayTouchResults() {
-        StringBuilder output = new StringBuilder();
-
-        output.append(String.format("%d,%d:%d,%d\n",
-                mPointerEvent.startX, mPointerEvent.startY, mPointerEvent.endX,
-                mPointerEvent.endY));
-
-        // display the submitted text
-        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-        builder.setTitle(R.string.drag_item_touch_dialog_title);
-        builder.setPositiveButton(R.string.OK, null);
-        builder.setMessage(output.toString());
-        AlertDialog diag = builder.create();
-        diag.show();
-    }
-
-    /**
-     * Clears all collected pointer results
-     */
-    private void resetTouchResults() {
-         mPointerEvent.startX = mPointerEvent.startY =
-                    mPointerEvent.endX = mPointerEvent.endY = -1;
-    }
-
-    /**
-     * Collects pointer touch information converting from relative to absolute before
-     * storing it as starting touch coordinates.
-     *
-     * @param event
-     * @param view
-     * @param pointerIndex
-     */
-    private void collectStartAction(MotionEvent event, View view) {
-        int offsetInScreen[] = new int[2];
-        view.getLocationOnScreen(offsetInScreen);
-        mPointerEvent.startX = (int)(event.getX() + offsetInScreen[0]);
-        mPointerEvent.startY = (int)(event.getY() + offsetInScreen[1]);
-    }
-
-    /**
-     * Collects pointer touch information converting from relative to absolute before
-     * storing it as ending touch coordinates.
-     *
-     * @param event
-     * @param view
-     * @param pointerIndex
-     */
-    private void collectEndAction(MotionEvent event, View view) {
-        int offsetInScreen[] = new int[2];
-        view.getLocationOnScreen(offsetInScreen);
-        mPointerEvent.endX = (int)(event.getX() + offsetInScreen[0]);
-        mPointerEvent.endY = (int)(event.getY() + offsetInScreen[1]);
-    }
-}
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test6DetailFragment.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test6DetailFragment.java
deleted file mode 100644
index 90bcfcf..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/Test6DetailFragment.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.webkit.WebView;
-
-public class Test6DetailFragment extends Fragment {
-    public static final String ARG_ITEM_ID = "item_id";
-    private final static String PAGE = "<html><body>"
-            + "This is test <b>6</b> for WebView text traversal test."
-            + "<p/><a href=\"http://google.com\">This is a link to google</a><br/>"
-            + "<h5>This is h5 text</h5>"
-            + "<a href=\"http://yahoo.com\">This is a link to yahoo</a>"
-            + "<p/><h4>This is h4 text</h4>" + "</body></html>";
-
-    public Test6DetailFragment() {
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
-        View rootView = inflater.inflate(R.layout.test6_detail_fragment, container, false);
-        WebView wv = (WebView) rootView.findViewById(R.id.test6WebView);
-        wv.loadData(PAGE, "text/html", null);
-        return rootView;
-    }
-}
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/TestGenericDetailFragment.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/TestGenericDetailFragment.java
deleted file mode 100644
index a7215c3..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/TestGenericDetailFragment.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.app.AlertDialog;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-public class TestGenericDetailFragment extends Fragment {
-    public static final String ARG_ITEM_ID = "item_id";
-    TestItems.TestItem mItem;
-
-    private class PointerEvent {
-        int startX;
-        int startY;
-        int endX;
-        int endY;
-    }
-
-    private final PointerEvent[] mPointerEvents = new PointerEvent[10];
-
-    public TestGenericDetailFragment() {
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        if (getArguments().containsKey(ARG_ITEM_ID)) {
-            mItem = TestItems.getTest(getArguments().getString(ARG_ITEM_ID));
-        }
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
-        View rootView = inflater.inflate(R.layout.test_results_detail_fragment, container, false);
-        if (mItem != null) {
-            ((TextView) rootView.findViewById(R.id.testResultsTextView)).setText(mItem.mName);
-        }
-
-        // listen to touch events to verify the multiPointerGesture APIs
-        // Since API Level 18
-        rootView.setOnTouchListener(new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-
-                switch(event.getAction() & MotionEvent.ACTION_MASK) {
-                    case MotionEvent.ACTION_DOWN:
-                        // Reset any collected touch coordinate results on the primary touch down
-                        resetTouchResults();
-                        // collect this event
-                        collectStartAction(event, v, 0);
-                        break;
-
-                    case MotionEvent.ACTION_POINTER_DOWN:
-                        // collect this event
-                        collectStartAction(event, v, getPointerIndex(event));
-                        break;
-
-                    case MotionEvent.ACTION_POINTER_UP:
-                        // collect this event
-                        collectEndAction(event, v, getPointerIndex(event));
-                        break;
-
-                    case MotionEvent.ACTION_UP:
-                        // collect this event
-                        collectEndAction(event, v, 0);
-                        // on the primary touch up display results collected for all pointers
-                        displayTouchResults();
-                        break;
-                }
-                return true;
-            }
-        });
-
-        return rootView;
-    }
-
-    /**
-     * Displays collected results from all pointers into a dialog view in the following
-     * format: "startX,startY:endX,endY" where each line represent data for a pointer if
-     * multiple pointers (fingers) were detected.
-     */
-    private void displayTouchResults() {
-        StringBuilder output = new StringBuilder();
-        for (int x = 0; x < mPointerEvents.length; x++) {
-            if (mPointerEvents[x].startX == -1)
-                break;
-
-            output.append(String.format("%d,%d:%d,%d\n",
-                    mPointerEvents[x].startX, mPointerEvents[x].startY, mPointerEvents[x].endX,
-                    mPointerEvents[x].endY));
-        }
-
-        // display the submitted text
-        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-        builder.setTitle(R.string.generic_item_touch_dialog_title);
-        builder.setPositiveButton(R.string.OK, null);
-        builder.setMessage(output.toString());
-        AlertDialog diag = builder.create();
-        diag.show();
-    }
-
-    /**
-     * Clears all collected pointer results
-     */
-    private void resetTouchResults() {
-        for (int x = 0; x < mPointerEvents.length; x++) {
-            if (mPointerEvents[x] == null)
-                mPointerEvents[x] = new PointerEvent();
-            mPointerEvents[x].startX = mPointerEvents[x].startY =
-                    mPointerEvents[x].endX = mPointerEvents[x].endY = -1;
-        }
-    }
-
-    /**
-     * Collects pointer touch information converting from relative to absolute before
-     * storing it as starting touch coordinates.
-     *
-     * @param event
-     * @param view
-     * @param pointerIndex
-     */
-    private void collectStartAction(MotionEvent event, View view, int pointerIndex) {
-        int offsetInScreen[] = new int[2];
-        view.getLocationOnScreen(offsetInScreen);
-        mPointerEvents[getPointerId(event)].startX =
-                (int)(event.getX(pointerIndex) + offsetInScreen[0]);
-        mPointerEvents[getPointerId(event)].startY =
-                (int)(event.getY(pointerIndex) + offsetInScreen[1]);
-    }
-
-    /**
-     * Collects pointer touch information converting from relative to absolute before
-     * storing it as ending touch coordinates.
-     *
-     * @param event
-     * @param view
-     * @param pointerIndex
-     */
-    private void collectEndAction(MotionEvent event, View view, int pointerIndex) {
-        int offsetInScreen[] = new int[2];
-        view.getLocationOnScreen(offsetInScreen);
-        mPointerEvents[getPointerId(event)].endX =
-                (int)(event.getX(pointerIndex) + offsetInScreen[0]);
-        mPointerEvents[getPointerId(event)].endY =
-                (int)(event.getY(pointerIndex) + offsetInScreen[1]);
-    }
-
-    private int getPointerId(MotionEvent event) {
-        return event.getPointerId(getPointerIndex(event));
-    }
-
-    private int getPointerIndex(MotionEvent event) {
-        return ((event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                >> MotionEvent.ACTION_POINTER_INDEX_SHIFT);
-    }
-}
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/TestItems.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/TestItems.java
deleted file mode 100644
index db6e693..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/TestItems.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class TestItems {
-    private static String LOG_TAG = TestItems.class.getSimpleName();
-    private static List<TestItem> ITEMS = new ArrayList<TestItem>();
-    private static Map<String, TestItem> ITEM_MAP = new HashMap<String, TestItem>();
-
-    public static class TestItem {
-        public String mId;
-        public String mName;
-        private final Class<Fragment> mClassFragment;
-        public String mTestDescription;
-
-        @SuppressWarnings("unchecked")
-        public TestItem(String id, String name, Class<?> clsf) {
-            mId = id;
-            mName = name;
-            mClassFragment = (Class<Fragment>) clsf;
-        }
-
-        @Override
-        public String toString() {
-            return mName;
-        }
-    }
-
-    static {
-        addTestItem(new TestItem("1", "Test 1", Test1DetailFragment.class));
-        addTestItem(new TestItem("2", "Test 2", Test2DetailFragment.class));
-        addTestItem(new TestItem("3", "Test 3", Test3DetailFragment.class));
-        addTestItem(new TestItem("4", "Test 4", Test4DetailFragment.class));
-        addTestItem(new TestItem("5", "Test 5", Test5DetailFragment.class));
-        addTestItem(new TestItem("6", "Test 6", Test6DetailFragment.class));
-        addTestItem(new TestItem("7", "Test 7", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("8", "Test 8", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("9", "Test 9", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("10", "Test 10", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("11", "Test 11", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("12", "Test 12", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("13", "Test 13", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("14", "Test 14", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("15", "Test 15", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("16", "Test 16", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("17", "Test 17", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("18", "Test 18", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("19", "Test 19", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("20", "Test 20", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("21", "Test 21", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("22", "Test 22", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("23", "Test 23", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("24", "Test 24", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("25", "Test 25", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("26", "Test 26", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("27", "Test 27", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("28", "Test 28", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("29", "Test 29", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("30", "Test 30", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("31", "Test 31", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("32", "Test 32", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("33", "Test 33", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("34", "Test 34", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("35", "Test 35", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("36", "Test 36", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("37", "Test 37", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("38", "Test 38", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("39", "Test 39", TestGenericDetailFragment.class));
-        addTestItem(new TestItem("40", "Test 40", TestGenericDetailFragment.class));
-    }
-
-    private static void addTestItem(TestItem item) {
-        ITEMS.add(item);
-        ITEM_MAP.put(item.mId, item);
-    }
-
-    public static List<TestItem> getTests() {
-        return ITEMS;
-    }
-
-    public static TestItem getTest(String id) {
-        return ITEM_MAP.get(id);
-    }
-
-    public static TestItem getTest(int pos) {
-        return ITEMS.get(pos);
-    }
-
-    public static Fragment getFragment(String id) {
-        try {
-            Fragment fragment = getTest(id).mClassFragment.newInstance();
-            Bundle arguments = new Bundle();
-            arguments.putString("item_id", id);
-            fragment.setArguments(arguments);
-            return fragment;
-        } catch (InstantiationException e) {
-            Log.e(LOG_TAG, "Exception", e);
-            return null;
-        } catch (IllegalAccessException e) {
-            Log.e(LOG_TAG, "Exception", e);
-            return null;
-        }
-    }
-}
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/TestListFragment.java b/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/TestListFragment.java
deleted file mode 100644
index 46f0f73..0000000
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/src/com/android/cts/uiautomator/TestListFragment.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.uiautomator;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.support.v4.app.ListFragment;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-
-public class TestListFragment extends ListFragment {
-
-    private static final String STATE_ACTIVATED_POSITION = "activated_position";
-
-    private Callbacks mCallbacks = sDummyCallbacks;
-    private int mActivatedPosition = ListView.INVALID_POSITION;
-
-    public interface Callbacks {
-
-        public void onItemSelected(String id);
-    }
-
-    private static Callbacks sDummyCallbacks = new Callbacks() {
-        @Override
-        public void onItemSelected(String id) {
-        }
-    };
-
-    public TestListFragment() {
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setListAdapter(new ArrayAdapter<TestItems.TestItem>(getActivity(),
-                R.layout.simple_list_item_selected, R.id.label, TestItems.getTests()));
-    }
-
-    @Override
-    public void onViewCreated(View view, Bundle savedState) {
-        super.onViewCreated(view, savedState);
-        if (savedState != null && savedState.containsKey(STATE_ACTIVATED_POSITION)) {
-            setActivatedPosition(savedState.getInt(STATE_ACTIVATED_POSITION));
-        }
-    }
-
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        if (!(activity instanceof Callbacks)) {
-            throw new IllegalStateException("Activity must implement fragment's callbacks.");
-        }
-
-        mCallbacks = (Callbacks) activity;
-    }
-
-    @Override
-    public void onDetach() {
-        super.onDetach();
-        mCallbacks = sDummyCallbacks;
-    }
-
-    @Override
-    public void onListItemClick(ListView listView, View view, int position, long id) {
-        super.onListItemClick(listView, view, position, id);
-        mCallbacks.onItemSelected(TestItems.getTest(position).mId);
-    }
-
-    @Override
-    public void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        if (mActivatedPosition != ListView.INVALID_POSITION) {
-            outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
-        }
-    }
-
-    public void setActivateOnItemClick(boolean activateOnItemClick) {
-        getListView().setChoiceMode(
-                activateOnItemClick ? ListView.CHOICE_MODE_SINGLE : ListView.CHOICE_MODE_NONE);
-    }
-
-    public void setActivatedPosition(int position) {
-        if (position == ListView.INVALID_POSITION) {
-            getListView().setItemChecked(mActivatedPosition, false);
-        } else {
-            getListView().setItemChecked(position, true);
-        }
-
-        mActivatedPosition = position;
-    }
-}
diff --git a/tests/video/Android.mk b/tests/video/Android.mk
new file mode 100644
index 0000000..191b8b2
--- /dev/null
+++ b/tests/video/Android.mk
@@ -0,0 +1,40 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# include both the 32 and 64 bit versions
+LOCAL_MULTILIB := both
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util ctstestrunner
+
+LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsVideoTestCases
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
+
diff --git a/tests/video/AndroidManifest.xml b/tests/video/AndroidManifest.xml
new file mode 100644
index 0000000..22dad9e
--- /dev/null
+++ b/tests/video/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.video.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="android.video.cts"
+            android:label="CTS tests for Video" >
+        <meta-data
+            android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+</manifest>
diff --git a/tests/video/AndroidTest.xml b/tests/video/AndroidTest.xml
new file mode 100644
index 0000000..0c98c42
--- /dev/null
+++ b/tests/video/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Video test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsVideoTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.video.cts" />
+    </test>
+</configuration>
diff --git a/tests/video/src/android/video/cts/CodecInfo.java b/tests/video/src/android/video/cts/CodecInfo.java
new file mode 100644
index 0000000..c1bf0a9
--- /dev/null
+++ b/tests/video/src/android/video/cts/CodecInfo.java
@@ -0,0 +1,108 @@
+/*
+ * 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 android.video.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.CodecProfileLevel;
+import android.media.MediaCodecInfo.VideoCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.util.Log;
+import android.util.Range;
+
+import java.io.IOException;
+
+/**
+ * Utility class for getting codec information like bit rate, fps, and etc.
+ * Uses public member variables instead of methods as this code is only for video benchmarking.
+ */
+public class CodecInfo {
+    /** bit rate in bps */
+    public int mBitRate = 0;
+    /** Frame rate */
+    public int mFps = 0;
+    /** if codec is supporting YUV semiplanar format */
+    public boolean mSupportSemiPlanar = false;
+    /** if codec is supporting YUV planar format */
+    public boolean mSupportPlanar = false;
+
+    private static final String TAG = "CodecInfo";
+    private static final String VIDEO_AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
+    /**
+     * Check if given codec with given (w,h) is supported.
+     * @param codecName codec name
+     * @param mimeType codec type in mime format like MediaFormat.MIMETYPE_VIDEO_AVC
+     * @param w video width
+     * @param h video height
+     * @return null if the configuration is not supported.
+     */
+    public static CodecInfo getSupportedFormatInfo(
+            String codecName, String mimeType, int w, int h) {
+        MediaCodec codec;
+        try {
+            codec = MediaCodec.createByCodecName(codecName);
+        } catch (IOException e) {
+            return null;
+        }
+
+        CodecCapabilities cap = codec.getCodecInfo().getCapabilitiesForType(mimeType);
+        if (cap.colorFormats.length == 0) {
+            Log.w(TAG, "no supported color format");
+            codec.release();
+            return null;
+        }
+
+        CodecInfo info = new CodecInfo();
+        for (int color : cap.colorFormats) {
+            if (color == CodecCapabilities.COLOR_FormatYUV420SemiPlanar) {
+                info.mSupportSemiPlanar = true;
+            }
+            if (color == CodecCapabilities.COLOR_FormatYUV420Planar) {
+                info.mSupportPlanar = true;
+            }
+        }
+        printIntArray("supported colors", cap.colorFormats);
+
+        VideoCapabilities vidCap = cap.getVideoCapabilities();
+        try {
+            info.mFps = vidCap.getSupportedFrameRatesFor(w, h).getUpper().intValue();
+        } catch (IllegalArgumentException e) {
+            Log.w(TAG, "unsupported size");
+            codec.release();
+            return null;
+        }
+        info.mBitRate = vidCap.getBitrateRange().getUpper();
+        Log.i(TAG, "test bit rate " + info.mBitRate + " fps " + info.mFps);
+        codec.release();
+        return info;
+    }
+
+    // for debugging
+    private static void printIntArray(String msg, int[] data) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(msg);
+        builder.append(":");
+        for (int e : data) {
+            builder.append(Integer.toHexString(e));
+            builder.append(",");
+        }
+        builder.deleteCharAt(builder.length() - 1);
+        Log.i(TAG, builder.toString());
+    }
+}
diff --git a/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java b/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
new file mode 100644
index 0000000..36fc9c2
--- /dev/null
+++ b/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
@@ -0,0 +1,1258 @@
+/*
+ * 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 android.video.cts;
+
+import android.cts.util.MediaUtils;
+import android.cts.util.DeviceReportLog;
+import android.graphics.ImageFormat;
+import android.graphics.Point;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.media.cts.CodecImage;
+import android.media.cts.CodecUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Range;
+
+import android.cts.util.CtsAndroidTestCase;
+import com.android.cts.util.ResultType;
+import com.android.cts.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+import com.android.cts.util.TimeoutReq;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.Random;
+
+/**
+ * This tries to test video encoder / decoder performance by running encoding / decoding
+ * without displaying the raw data. To make things simpler, encoder is used to encode synthetic
+ * data and decoder is used to decode the encoded video. This approach does not work where
+ * there is only decoder. Performance index is total time taken for encoding and decoding
+ * the whole frames.
+ * To prevent sacrificing quality for faster encoding / decoding, randomly selected pixels are
+ * compared with the original image. As the pixel comparison can slow down the decoding process,
+ * only some randomly selected pixels are compared. As there can be only one performance index,
+ * error above certain threshold in pixel value will be treated as an error.
+ */
+public class VideoEncoderDecoderTest extends CtsAndroidTestCase {
+    private static final String TAG = "VideoEncoderDecoderTest";
+    // this wait time affects fps as too big value will work as a blocker if device fps
+    // is not very high.
+    private static final long VIDEO_CODEC_WAIT_TIME_US = 5000;
+    private static final boolean VERBOSE = false;
+    private static final String VIDEO_AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
+    private static final String VIDEO_VP8 = MediaFormat.MIMETYPE_VIDEO_VP8;
+    private static final String VIDEO_H263 = MediaFormat.MIMETYPE_VIDEO_H263;
+    private static final String VIDEO_MPEG4 = MediaFormat.MIMETYPE_VIDEO_MPEG4;
+    private int mCurrentTestRound = 0;
+    private double[][] mEncoderFrameTimeDiff = null;
+    private double[][] mDecoderFrameTimeDiff = null;
+    // i frame interval for encoder
+    private static final int KEY_I_FRAME_INTERVAL = 5;
+    private static final int MOVING_AVERAGE_NUM = 10;
+
+    private static final int Y_CLAMP_MIN = 16;
+    private static final int Y_CLAMP_MAX = 235;
+    private static final int YUV_PLANE_ADDITIONAL_LENGTH = 200;
+    private ByteBuffer mYBuffer, mYDirectBuffer;
+    private ByteBuffer mUVBuffer, mUVDirectBuffer;
+    private int mSrcColorFormat;
+    private int mDstColorFormat;
+    private int mBufferWidth;
+    private int mBufferHeight;
+    private int mVideoWidth;
+    private int mVideoHeight;
+    private int mFrameRate;
+
+    private MediaFormat mEncInputFormat;
+    private MediaFormat mEncOutputFormat;
+    private MediaFormat mDecOutputFormat;
+
+    private LinkedList<Pair<ByteBuffer, BufferInfo>> mEncodedOutputBuffer;
+    // check this many pixels per each decoded frame
+    // checking too many points decreases decoder frame rates a lot.
+    private static final int PIXEL_CHECK_PER_FRAME = 1000;
+    // RMS error in pixel values above this will be treated as error.
+    private static final double PIXEL_RMS_ERROR_MARGAIN = 20.0;
+    private double mRmsErrorMargain = PIXEL_RMS_ERROR_MARGAIN;
+    private Random mRandom;
+
+    private class TestConfig {
+        public boolean mTestPixels = true;
+        public boolean mTestResult = false;
+        public boolean mReportFrameTime = false;
+        public int mTotalFrames = 300;
+        public int mMaxTimeMs = 120000;  // 2 minutes
+        public int mNumberOfRepeat = 10;
+    }
+
+    private TestConfig mTestConfig;
+
+    private DeviceReportLog mReportLog;
+
+    @Override
+    protected void setUp() throws Exception {
+        mEncodedOutputBuffer = new LinkedList<Pair<ByteBuffer, BufferInfo>>();
+        // Use time as a seed, hoping to prevent checking pixels in the same pattern
+        long now = System.currentTimeMillis();
+        mRandom = new Random(now);
+        mTestConfig = new TestConfig();
+        mReportLog = new DeviceReportLog();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mEncodedOutputBuffer.clear();
+        mEncodedOutputBuffer = null;
+        mYBuffer = null;
+        mUVBuffer = null;
+        mYDirectBuffer = null;
+        mUVDirectBuffer = null;
+        mRandom = null;
+        mTestConfig = null;
+        mReportLog.deliverReportToHost(getInstrumentation());
+        super.tearDown();
+    }
+
+    private String getEncoderName(String mime) {
+        return getCodecName(mime, true /* isEncoder */);
+    }
+
+    private String getDecoderName(String mime) {
+        return getCodecName(mime, false /* isEncoder */);
+    }
+
+    private String getCodecName(String mime, boolean isEncoder) {
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        for (MediaCodecInfo info : mcl.getCodecInfos()) {
+            if (info.isEncoder() != isEncoder) {
+                continue;
+            }
+            CodecCapabilities caps = null;
+            try {
+                caps = info.getCapabilitiesForType(mime);
+            } catch (IllegalArgumentException e) {  // mime is not supported
+                continue;
+            }
+            return info.getName();
+        }
+        return null;
+    }
+
+    private String[] getEncoderName(String mime, boolean isGoog) {
+        return getCodecName(mime, isGoog, true /* isEncoder */);
+    }
+
+    private String[] getDecoderName(String mime, boolean isGoog) {
+        return getCodecName(mime, isGoog, false /* isEncoder */);
+    }
+
+    private String[] getCodecName(String mime, boolean isGoog, boolean isEncoder) {
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        ArrayList<String> result = new ArrayList<String>();
+        for (MediaCodecInfo info : mcl.getCodecInfos()) {
+            if (info.isEncoder() != isEncoder
+                    || info.getName().toLowerCase().startsWith("omx.google.") != isGoog) {
+                continue;
+            }
+            CodecCapabilities caps = null;
+            try {
+                caps = info.getCapabilitiesForType(mime);
+            } catch (IllegalArgumentException e) {  // mime is not supported
+                continue;
+            }
+            result.add(info.getName());
+        }
+        return result.toArray(new String[result.size()]);
+    }
+
+    public void testAvc0176x0144() throws Exception {
+        doTestDefault(VIDEO_AVC, 176, 144);
+    }
+
+    public void testAvc0352x0288() throws Exception {
+        doTestDefault(VIDEO_AVC, 352, 288);
+    }
+
+    public void testAvc0720x0480() throws Exception {
+        doTestDefault(VIDEO_AVC, 720, 480);
+    }
+
+    public void testAvc1280x0720() throws Exception {
+        doTestDefault(VIDEO_AVC, 1280, 720);
+    }
+
+    /**
+     * resolution intentionally set to 1072 not 1080
+     * as 1080 is not multiple of 16, and it requires additional setting like stride
+     * which is not specified in API documentation.
+     */
+    public void testAvc1920x1072() throws Exception {
+        doTestDefault(VIDEO_AVC, 1920, 1072);
+    }
+
+    // Avc tests
+    public void testAvc0320x0240Other() throws Exception {
+        doTestOther(VIDEO_AVC, 320, 240);
+    }
+
+    public void testAvc0320x0240Goog() throws Exception {
+        doTestGoog(VIDEO_AVC, 320, 240);
+    }
+
+    public void testAvc0720x0480Other() throws Exception {
+        doTestOther(VIDEO_AVC, 720, 480);
+    }
+
+    public void testAvc0720x0480Goog() throws Exception {
+        doTestGoog(VIDEO_AVC, 720, 480);
+    }
+
+    @TimeoutReq(minutes = 10)
+    public void testAvc1280x0720Other() throws Exception {
+        doTestOther(VIDEO_AVC, 1280, 720);
+    }
+
+    @TimeoutReq(minutes = 10)
+    public void testAvc1280x0720Goog() throws Exception {
+        doTestGoog(VIDEO_AVC, 1280, 720);
+    }
+
+    @TimeoutReq(minutes = 10)
+    public void testAvc1920x1080Other() throws Exception {
+        doTestOther(VIDEO_AVC, 1920, 1080);
+    }
+
+    @TimeoutReq(minutes = 10)
+    public void testAvc1920x1080Goog() throws Exception {
+        doTestGoog(VIDEO_AVC, 1920, 1080);
+    }
+
+    // Vp8 tests
+    public void testVp80320x0180Other() throws Exception {
+        doTestOther(VIDEO_VP8, 320, 180);
+    }
+
+    public void testVp80320x0180Goog() throws Exception {
+        doTestGoog(VIDEO_VP8, 320, 180);
+    }
+
+    public void testVp80640x0360Other() throws Exception {
+        doTestOther(VIDEO_VP8, 640, 360);
+    }
+
+    public void testVp80640x0360Goog() throws Exception {
+        doTestGoog(VIDEO_VP8, 640, 360);
+    }
+
+    @TimeoutReq(minutes = 10)
+    public void testVp81280x0720Other() throws Exception {
+        doTestOther(VIDEO_VP8, 1280, 720);
+    }
+
+    @TimeoutReq(minutes = 10)
+    public void testVp81280x0720Goog() throws Exception {
+        doTestGoog(VIDEO_VP8, 1280, 720);
+    }
+
+    @TimeoutReq(minutes = 10)
+    public void testVp81920x1080Other() throws Exception {
+        doTestOther(VIDEO_VP8, 1920, 1080);
+    }
+
+    @TimeoutReq(minutes = 10)
+    public void testVp81920x1080Goog() throws Exception {
+        doTestGoog(VIDEO_VP8, 1920, 1080);
+    }
+
+    // H263 tests
+    public void testH2630176x0144Other() throws Exception {
+        doTestOther(VIDEO_H263, 176, 144);
+    }
+
+    public void testH2630176x0144Goog() throws Exception {
+        doTestGoog(VIDEO_H263, 176, 144);
+    }
+
+    public void testH2630352x0288Other() throws Exception {
+        doTestOther(VIDEO_H263, 352, 288);
+    }
+
+    public void testH2630352x0288Goog() throws Exception {
+        doTestGoog(VIDEO_H263, 352, 288);
+    }
+
+    // Mpeg4 tests
+    public void testMpeg40176x0144Other() throws Exception {
+        doTestOther(VIDEO_MPEG4, 176, 144);
+    }
+
+    public void testMpeg40176x0144Goog() throws Exception {
+        doTestGoog(VIDEO_MPEG4, 176, 144);
+    }
+
+    public void testMpeg40352x0288Other() throws Exception {
+        doTestOther(VIDEO_MPEG4, 352, 288);
+    }
+
+    public void testMpeg40352x0288Goog() throws Exception {
+        doTestGoog(VIDEO_MPEG4, 352, 288);
+    }
+
+    public void testMpeg40640x0480Other() throws Exception {
+        doTestOther(VIDEO_MPEG4, 640, 480);
+    }
+
+    public void testMpeg40640x0480Goog() throws Exception {
+        doTestGoog(VIDEO_MPEG4, 640, 480);
+    }
+
+    @TimeoutReq(minutes = 10)
+    public void testMpeg41280x0720Other() throws Exception {
+        doTestOther(VIDEO_MPEG4, 1280, 720);
+    }
+
+    @TimeoutReq(minutes = 10)
+    public void testMpeg41280x0720Goog() throws Exception {
+        doTestGoog(VIDEO_MPEG4, 1280, 720);
+    }
+
+    private boolean isSrcSemiPlanar() {
+        return mSrcColorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
+    }
+
+    private boolean isSrcFlexYUV() {
+        return mSrcColorFormat == CodecCapabilities.COLOR_FormatYUV420Flexible;
+    }
+
+    private boolean isDstSemiPlanar() {
+        return mDstColorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
+    }
+
+    private boolean isDstFlexYUV() {
+        return mDstColorFormat == CodecCapabilities.COLOR_FormatYUV420Flexible;
+    }
+
+    private static int getColorFormat(CodecInfo info) {
+        if (info.mSupportSemiPlanar) {
+            return CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
+        } else if (info.mSupportPlanar) {
+            return CodecCapabilities.COLOR_FormatYUV420Planar;
+        } else {
+            // FlexYUV must be supported
+            return CodecCapabilities.COLOR_FormatYUV420Flexible;
+        }
+    }
+
+    private void doTestGoog(String mimeType, int w, int h) throws Exception {
+        mTestConfig.mTestPixels = false;
+        mTestConfig.mTestResult = true;
+        mTestConfig.mTotalFrames = 3000;
+        mTestConfig.mNumberOfRepeat = 2;
+        doTest(true /* isGoog */, mimeType, w, h);
+    }
+
+    private void doTestOther(String mimeType, int w, int h) throws Exception {
+        mTestConfig.mTestPixels = false;
+        mTestConfig.mTestResult = true;
+        mTestConfig.mTotalFrames = 3000;
+        mTestConfig.mNumberOfRepeat = 2;
+        doTest(false /* isGoog */, mimeType, w, h);
+    }
+
+    private void doTestDefault(String mimeType, int w, int h) throws Exception {
+        String encoderName = getEncoderName(mimeType);
+        if (encoderName == null) {
+            Log.i(TAG, "Encoder for " + mimeType + " not found");
+            return;
+        }
+
+        String decoderName = getDecoderName(mimeType);
+        if (decoderName == null) {
+            Log.i(TAG, "Encoder for " + mimeType + " not found");
+            return;
+        }
+
+        doTestByName(encoderName, decoderName, mimeType, w, h);
+    }
+
+    /**
+     * Run encoding / decoding test for given mimeType of codec
+     * @param isGoog test google or non-google codec.
+     * @param mimeType like video/avc
+     * @param w video width
+     * @param h video height
+     */
+    private void doTest(boolean isGoog, String mimeType, int w, int h)
+            throws Exception {
+        String[] encoderNames = getEncoderName(mimeType, isGoog);
+        if (encoderNames.length == 0) {
+            Log.i(TAG, isGoog ? "Google " : "Non-google "
+                    + "encoder for " + mimeType + " not found");
+            return;
+        }
+
+        String[] decoderNames = getDecoderName(mimeType, isGoog);
+        if (decoderNames.length == 0) {
+            Log.i(TAG, isGoog ? "Google " : "Non-google "
+                    + "decoder for " + mimeType + " not found");
+            return;
+        }
+
+        for (String encoderName: encoderNames) {
+            for (String decoderName: decoderNames) {
+                doTestByName(encoderName, decoderName, mimeType, w, h);
+            }
+        }
+    }
+
+    private void doTestByName(
+            String encoderName, String decoderName, String mimeType, int w, int h)
+            throws Exception {
+        CodecInfo infoEnc = CodecInfo.getSupportedFormatInfo(encoderName, mimeType, w, h);
+        if (infoEnc == null) {
+            Log.i(TAG, "Encoder " + mimeType + " with " + w + "," + h + " not supported");
+            return;
+        }
+        CodecInfo infoDec = CodecInfo.getSupportedFormatInfo(decoderName, mimeType, w, h);
+        assertNotNull(infoDec);
+        mVideoWidth = w;
+        mVideoHeight = h;
+
+        mSrcColorFormat = getColorFormat(infoEnc);
+        mDstColorFormat = getColorFormat(infoDec);
+        Log.i(TAG, "Testing video resolution " + w + "x" + h +
+                   ": enc format " + mSrcColorFormat +
+                   ", dec format " + mDstColorFormat);
+
+        initYUVPlane(w + YUV_PLANE_ADDITIONAL_LENGTH, h + YUV_PLANE_ADDITIONAL_LENGTH);
+        mEncoderFrameTimeDiff =
+                new double[mTestConfig.mNumberOfRepeat][mTestConfig.mTotalFrames - 1];
+        mDecoderFrameTimeDiff =
+                new double[mTestConfig.mNumberOfRepeat][mTestConfig.mTotalFrames - 1];
+        double[] encoderFpsResults = new double[mTestConfig.mNumberOfRepeat];
+        double[] decoderFpsResults = new double[mTestConfig.mNumberOfRepeat];
+        double[] totalFpsResults = new double[mTestConfig.mNumberOfRepeat];
+        double[] decoderRmsErrorResults = new double[mTestConfig.mNumberOfRepeat];
+        boolean success = true;
+        for (int i = 0; i < mTestConfig.mNumberOfRepeat && success; i++) {
+            mCurrentTestRound = i;
+            MediaFormat format = new MediaFormat();
+            format.setString(MediaFormat.KEY_MIME, mimeType);
+            format.setInteger(MediaFormat.KEY_BIT_RATE, infoEnc.mBitRate);
+            format.setInteger(MediaFormat.KEY_WIDTH, w);
+            format.setInteger(MediaFormat.KEY_HEIGHT, h);
+            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mSrcColorFormat);
+            format.setInteger(MediaFormat.KEY_FRAME_RATE, infoEnc.mFps);
+            mFrameRate = infoEnc.mFps;
+            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, KEY_I_FRAME_INTERVAL);
+
+            double encodingTime = runEncoder(encoderName, format, mTestConfig.mTotalFrames);
+            // re-initialize format for decoder
+            format = new MediaFormat();
+            format.setString(MediaFormat.KEY_MIME, mimeType);
+            format.setInteger(MediaFormat.KEY_WIDTH, w);
+            format.setInteger(MediaFormat.KEY_HEIGHT, h);
+            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mDstColorFormat);
+            double[] decoderResult = runDecoder(decoderName, format);
+            if (decoderResult == null) {
+                success = false;
+            } else {
+                double decodingTime = decoderResult[0];
+                decoderRmsErrorResults[i] = decoderResult[1];
+                encoderFpsResults[i] = (double)mTestConfig.mTotalFrames / encodingTime * 1000.0;
+                decoderFpsResults[i] = (double)mTestConfig.mTotalFrames / decodingTime * 1000.0;
+                totalFpsResults[i] =
+                        (double)mTestConfig.mTotalFrames / (encodingTime + decodingTime) * 1000.0;
+            }
+
+            // clear things for re-start
+            mEncodedOutputBuffer.clear();
+            // it will be good to clean everything to make every run the same.
+            System.gc();
+        }
+        mReportLog.printArray("encoder", encoderFpsResults, ResultType.HIGHER_BETTER,
+                ResultUnit.FPS);
+        mReportLog.printArray("rms error", decoderRmsErrorResults, ResultType.LOWER_BETTER,
+                ResultUnit.NONE);
+        mReportLog.printArray("decoder", decoderFpsResults, ResultType.HIGHER_BETTER,
+                ResultUnit.FPS);
+        mReportLog.printArray("encoder decoder", totalFpsResults, ResultType.HIGHER_BETTER,
+                ResultUnit.FPS);
+        mReportLog.printValue(mimeType + " encoder average fps for " + w + "x" + h,
+                Stat.getAverage(encoderFpsResults), ResultType.HIGHER_BETTER, ResultUnit.FPS);
+        mReportLog.printValue(mimeType + " decoder average fps for " + w + "x" + h,
+                Stat.getAverage(decoderFpsResults), ResultType.HIGHER_BETTER, ResultUnit.FPS);
+        mReportLog.printSummary("encoder decoder", Stat.getAverage(totalFpsResults),
+                ResultType.HIGHER_BETTER, ResultUnit.FPS);
+
+        boolean encTestPassed = false;
+        boolean decTestPassed = false;
+        double[] measuredFps = new double[mTestConfig.mNumberOfRepeat];
+        String[] resultRawData = new String[mTestConfig.mNumberOfRepeat];
+        for (int i = 0; i < mTestConfig.mNumberOfRepeat; i++) {
+            // make sure that rms error is not too big.
+            if (decoderRmsErrorResults[i] >= mRmsErrorMargain) {
+                fail("rms error is bigger than the limit "
+                        + decoderRmsErrorResults[i] + " vs " + mRmsErrorMargain);
+            }
+
+            if (mTestConfig.mReportFrameTime) {
+                mReportLog.printValue(
+                        "encodertest#" + i + ": " + Arrays.toString(mEncoderFrameTimeDiff[i]),
+                        0, ResultType.NEUTRAL, ResultUnit.NONE);
+                mReportLog.printValue(
+                        "decodertest#" + i + ": " + Arrays.toString(mDecoderFrameTimeDiff[i]),
+                        0, ResultType.NEUTRAL, ResultUnit.NONE);
+            }
+
+            if (mTestConfig.mTestResult) {
+                double[] avgs = MediaUtils.calculateMovingAverage(
+                        mEncoderFrameTimeDiff[i], MOVING_AVERAGE_NUM);
+                double encMin = Stat.getMin(avgs);
+                double encMax = Stat.getMax(avgs);
+                double encAvg = MediaUtils.getAverage(mEncoderFrameTimeDiff[i]);
+                double encStdev = MediaUtils.getStdev(avgs);
+                String prefix = "codec=" + encoderName + " round=" + i +
+                        " EncInputFormat=" + mEncInputFormat +
+                        " EncOutputFormat=" + mEncOutputFormat;
+                String result =
+                        MediaUtils.logResults(mReportLog, prefix, encMin, encMax, encAvg, encStdev);
+                double measuredEncFps = 1000000000 / encMin;
+                resultRawData[i] = result;
+                measuredFps[i] = measuredEncFps;
+                if (!encTestPassed) {
+                    encTestPassed = MediaUtils.verifyResults(
+                            encoderName, mimeType, w, h, measuredEncFps);
+                }
+
+                avgs = MediaUtils.calculateMovingAverage(
+                        mDecoderFrameTimeDiff[i], MOVING_AVERAGE_NUM);
+                double decMin = Stat.getMin(avgs);
+                double decMax = Stat.getMax(avgs);
+                double decAvg = MediaUtils.getAverage(mDecoderFrameTimeDiff[i]);
+                double decStdev = MediaUtils.getStdev(avgs);
+                prefix = "codec=" + decoderName + " size=" + w + "x" + h + " round=" + i +
+                        " DecOutputFormat=" + mDecOutputFormat;
+                MediaUtils.logResults(mReportLog, prefix, decMin, decMax, decAvg, decStdev);
+                double measuredDecFps = 1000000000 / decMin;
+                if (!decTestPassed) {
+                    decTestPassed = MediaUtils.verifyResults(
+                            decoderName, mimeType, w, h, measuredDecFps);
+                }
+            }
+        }
+
+        if (mTestConfig.mTestResult) {
+            if (!encTestPassed) {
+                Range<Double> reportedRange =
+                    MediaUtils.getAchievableFrameRatesFor(encoderName, mimeType, w, h);
+                String failMessage =
+                    MediaUtils.getErrorMessage(reportedRange, measuredFps, resultRawData);
+                fail(failMessage);
+            }
+            // Decoder result will be verified in VideoDecoderPerfTest
+            // if (!decTestPassed) {
+            //     fail("Measured fps for " + decoderName +
+            //             " doesn't match with reported achievable frame rates.");
+            // }
+        }
+        measuredFps = null;
+        resultRawData = null;
+    }
+
+    /**
+     * run encoder benchmarking
+     * @param encoderName encoder name
+     * @param format format of media to encode
+     * @param totalFrames total number of frames to encode
+     * @return time taken in ms to encode the frames. This does not include initialization time.
+     */
+    private double runEncoder(String encoderName, MediaFormat format, int totalFrames) {
+        MediaCodec codec = null;
+        try {
+            codec = MediaCodec.createByCodecName(encoderName);
+            codec.configure(
+                    format,
+                    null /* surface */,
+                    null /* crypto */,
+                    MediaCodec.CONFIGURE_FLAG_ENCODE);
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "codec '" + encoderName + "' failed configuration.");
+            codec.release();
+            assertTrue("codec '" + encoderName + "' failed configuration.", false);
+        } catch (IOException | NullPointerException e) {
+            Log.i(TAG, "could not find codec for " + format);
+            return Double.NaN;
+        }
+        codec.start();
+        mEncInputFormat = codec.getInputFormat();
+        ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
+
+        int numBytesSubmitted = 0;
+        int numBytesDequeued = 0;
+        int inFramesCount = 0;
+        long lastOutputTimeNs = 0;
+        long start = System.currentTimeMillis();
+        while (true) {
+            int index;
+
+            if (inFramesCount < totalFrames) {
+                index = codec.dequeueInputBuffer(VIDEO_CODEC_WAIT_TIME_US /* timeoutUs */);
+                if (index != MediaCodec.INFO_TRY_AGAIN_LATER) {
+                    int size;
+                    boolean eos = (inFramesCount == (totalFrames - 1));
+                    if (!eos && ((System.currentTimeMillis() - start) > mTestConfig.mMaxTimeMs)) {
+                        eos = true;
+                    }
+                    // when encoder only supports flexYUV, use Image only; otherwise,
+                    // use ByteBuffer & Image each on half of the frames to test both
+                    if (isSrcFlexYUV() || inFramesCount % 2 == 0) {
+                        Image image = codec.getInputImage(index);
+                        // image should always be available
+                        assertTrue(image != null);
+                        size = queueInputImageEncoder(
+                                codec, image, index, inFramesCount,
+                                eos ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+                    } else {
+                        ByteBuffer buffer = codec.getInputBuffer(index);
+                        size = queueInputBufferEncoder(
+                                codec, buffer, index, inFramesCount,
+                                eos ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+                    }
+                    inFramesCount++;
+                    numBytesSubmitted += size;
+                    if (VERBOSE) {
+                        Log.d(TAG, "queued " + size + " bytes of input data, frame " +
+                                (inFramesCount - 1));
+                    }
+
+                }
+            }
+            MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+            index = codec.dequeueOutputBuffer(info, VIDEO_CODEC_WAIT_TIME_US /* timeoutUs */);
+            if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
+            } else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                mEncOutputFormat = codec.getOutputFormat();
+            } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+                codecOutputBuffers = codec.getOutputBuffers();
+            } else if (index >= 0) {
+                if (lastOutputTimeNs > 0) {
+                    int pos = mEncodedOutputBuffer.size() - 1;
+                    if (pos < mEncoderFrameTimeDiff[mCurrentTestRound].length) {
+                        long diff = System.nanoTime() - lastOutputTimeNs;
+                        mEncoderFrameTimeDiff[mCurrentTestRound][pos] = diff;
+                    }
+                }
+                lastOutputTimeNs = System.nanoTime();
+
+                dequeueOutputBufferEncoder(codec, codecOutputBuffers, index, info);
+                numBytesDequeued += info.size;
+                if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                    if (VERBOSE) {
+                        Log.d(TAG, "dequeued output EOS.");
+                    }
+                    break;
+                }
+                if (VERBOSE) {
+                    Log.d(TAG, "dequeued " + info.size + " bytes of output data.");
+                }
+            }
+        }
+        long finish = System.currentTimeMillis();
+        int validDataNum = Math.min(mEncodedOutputBuffer.size() - 1,
+                mEncoderFrameTimeDiff[mCurrentTestRound].length);
+        mEncoderFrameTimeDiff[mCurrentTestRound] =
+                Arrays.copyOf(mEncoderFrameTimeDiff[mCurrentTestRound], validDataNum);
+        if (VERBOSE) {
+            Log.d(TAG, "queued a total of " + numBytesSubmitted + "bytes, "
+                    + "dequeued " + numBytesDequeued + " bytes.");
+        }
+        codec.stop();
+        codec.release();
+        codec = null;
+        return (double)(finish - start);
+    }
+
+    /**
+     * Fills input buffer for encoder from YUV buffers.
+     * @return size of enqueued data.
+     */
+    private int queueInputBufferEncoder(
+            MediaCodec codec, ByteBuffer buffer, int index, int frameCount, int flags) {
+        buffer.clear();
+
+        Point origin = getOrigin(frameCount);
+        // Y color first
+        int srcOffsetY = origin.x + origin.y * mBufferWidth;
+        final byte[] yBuffer = mYBuffer.array();
+        for (int i = 0; i < mVideoHeight; i++) {
+            buffer.put(yBuffer, srcOffsetY, mVideoWidth);
+            srcOffsetY += mBufferWidth;
+        }
+        if (isSrcSemiPlanar()) {
+            int srcOffsetU = origin.y / 2 * mBufferWidth + origin.x / 2 * 2;
+            final byte[] uvBuffer = mUVBuffer.array();
+            for (int i = 0; i < mVideoHeight / 2; i++) {
+                buffer.put(uvBuffer, srcOffsetU, mVideoWidth);
+                srcOffsetU += mBufferWidth;
+            }
+        } else {
+            int srcOffsetU = origin.y / 2 * mBufferWidth / 2 + origin.x / 2;
+            int srcOffsetV = srcOffsetU + mBufferWidth / 2 * mBufferHeight / 2;
+            final byte[] uvBuffer = mUVBuffer.array();
+            for (int i = 0; i < mVideoHeight / 2; i++) { //U only
+                buffer.put(uvBuffer, srcOffsetU, mVideoWidth / 2);
+                srcOffsetU += mBufferWidth / 2;
+            }
+            for (int i = 0; i < mVideoHeight / 2; i++) { //V only
+                buffer.put(uvBuffer, srcOffsetV, mVideoWidth / 2);
+                srcOffsetV += mBufferWidth / 2;
+            }
+        }
+        int size = mVideoHeight * mVideoWidth * 3 / 2;
+        long ptsUsec = computePresentationTime(frameCount);
+
+        codec.queueInputBuffer(index, 0 /* offset */, size, ptsUsec /* timeUs */, flags);
+        if (VERBOSE && (frameCount == 0)) {
+            printByteArray("Y ", mYBuffer.array(), 0, 20);
+            printByteArray("UV ", mUVBuffer.array(), 0, 20);
+            printByteArray("UV ", mUVBuffer.array(), mBufferWidth * 60, 20);
+        }
+        return size;
+    }
+
+    class YUVImage extends CodecImage {
+        private final int mImageWidth;
+        private final int mImageHeight;
+        private final Plane[] mPlanes;
+
+        YUVImage(
+                Point origin,
+                int imageWidth, int imageHeight,
+                int arrayWidth, int arrayHeight,
+                boolean semiPlanar,
+                ByteBuffer bufferY, ByteBuffer bufferUV) {
+            mImageWidth = imageWidth;
+            mImageHeight = imageHeight;
+            ByteBuffer dupY = bufferY.duplicate();
+            ByteBuffer dupUV = bufferUV.duplicate();
+            mPlanes = new Plane[3];
+
+            int srcOffsetY = origin.x + origin.y * arrayWidth;
+
+            mPlanes[0] = new YUVPlane(
+                        mImageWidth, mImageHeight, arrayWidth, 1,
+                        dupY, srcOffsetY);
+
+            if (semiPlanar) {
+                int srcOffsetUV = origin.y / 2 * arrayWidth + origin.x / 2 * 2;
+
+                mPlanes[1] = new YUVPlane(
+                        mImageWidth / 2, mImageHeight / 2, arrayWidth, 2,
+                        dupUV, srcOffsetUV);
+                mPlanes[2] = new YUVPlane(
+                        mImageWidth / 2, mImageHeight / 2, arrayWidth, 2,
+                        dupUV, srcOffsetUV + 1);
+            } else {
+                int srcOffsetU = origin.y / 2 * arrayWidth / 2 + origin.x / 2;
+                int srcOffsetV = srcOffsetU + arrayWidth / 2 * arrayHeight / 2;
+
+                mPlanes[1] = new YUVPlane(
+                        mImageWidth / 2, mImageHeight / 2, arrayWidth / 2, 1,
+                        dupUV, srcOffsetU);
+                mPlanes[2] = new YUVPlane(
+                        mImageWidth / 2, mImageHeight / 2, arrayWidth / 2, 1,
+                        dupUV, srcOffsetV);
+            }
+        }
+
+        @Override
+        public int getFormat() {
+            return ImageFormat.YUV_420_888;
+        }
+
+        @Override
+        public int getWidth() {
+            return mImageWidth;
+        }
+
+        @Override
+        public int getHeight() {
+            return mImageHeight;
+        }
+
+        @Override
+        public long getTimestamp() {
+            return 0;
+        }
+
+        @Override
+        public Plane[] getPlanes() {
+            return mPlanes;
+        }
+
+        @Override
+        public void close() {
+            mPlanes[0] = null;
+            mPlanes[1] = null;
+            mPlanes[2] = null;
+        }
+
+        class YUVPlane extends CodecImage.Plane {
+            private final int mRowStride;
+            private final int mPixelStride;
+            private final ByteBuffer mByteBuffer;
+
+            YUVPlane(int w, int h, int rowStride, int pixelStride,
+                    ByteBuffer buffer, int offset) {
+                mRowStride = rowStride;
+                mPixelStride = pixelStride;
+
+                // only safe to access length bytes starting from buffer[offset]
+                int length = (h - 1) * rowStride + (w - 1) * pixelStride + 1;
+
+                buffer.position(offset);
+                mByteBuffer = buffer.slice();
+                mByteBuffer.limit(length);
+            }
+
+            @Override
+            public int getRowStride() {
+                return mRowStride;
+            }
+
+            @Override
+            public int getPixelStride() {
+                return mPixelStride;
+            }
+
+            @Override
+            public ByteBuffer getBuffer() {
+                return mByteBuffer;
+            }
+        }
+    }
+
+    /**
+     * Fills input image for encoder from YUV buffers.
+     * @return size of enqueued data.
+     */
+    private int queueInputImageEncoder(
+            MediaCodec codec, Image image, int index, int frameCount, int flags) {
+        assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
+
+
+        Point origin = getOrigin(frameCount);
+
+        // Y color first
+        CodecImage srcImage = new YUVImage(
+                origin,
+                mVideoWidth, mVideoHeight,
+                mBufferWidth, mBufferHeight,
+                isSrcSemiPlanar(),
+                mYDirectBuffer, mUVDirectBuffer);
+
+        CodecUtils.copyFlexYUVImage(image, srcImage);
+
+        int size = mVideoHeight * mVideoWidth * 3 / 2;
+        long ptsUsec = computePresentationTime(frameCount);
+
+        codec.queueInputBuffer(index, 0 /* offset */, size, ptsUsec /* timeUs */, flags);
+        if (VERBOSE && (frameCount == 0)) {
+            printByteArray("Y ", mYBuffer.array(), 0, 20);
+            printByteArray("UV ", mUVBuffer.array(), 0, 20);
+            printByteArray("UV ", mUVBuffer.array(), mBufferWidth * 60, 20);
+        }
+        return size;
+    }
+
+    /**
+     * Dequeue encoded data from output buffer and store for later usage.
+     */
+    private void dequeueOutputBufferEncoder(
+            MediaCodec codec, ByteBuffer[] outputBuffers,
+            int index, MediaCodec.BufferInfo info) {
+        ByteBuffer output = outputBuffers[index];
+        int l = info.size;
+        ByteBuffer copied = ByteBuffer.allocate(l);
+        output.get(copied.array(), 0, l);
+        BufferInfo savedInfo = new BufferInfo();
+        savedInfo.set(0, l, info.presentationTimeUs, info.flags);
+        mEncodedOutputBuffer.addLast(Pair.create(copied, savedInfo));
+        codec.releaseOutputBuffer(index, false /* render */);
+    }
+
+    /**
+     * run encoder benchmarking with encoded stream stored from encoding phase
+     * @param decoderName decoder name
+     * @param format format of media to decode
+     * @return returns length-2 array with 0: time for decoding, 1 : rms error of pixels
+     */
+    private double[] runDecoder(String decoderName, MediaFormat format) {
+        MediaCodec codec = null;
+        try {
+            codec = MediaCodec.createByCodecName(decoderName);
+        } catch (IOException | NullPointerException e) {
+            Log.i(TAG, "could not find decoder for " + format);
+            return null;
+        }
+        codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
+        codec.start();
+        ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
+
+        double totalErrorSquared = 0;
+
+        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+        boolean sawOutputEOS = false;
+        int inputLeft = mEncodedOutputBuffer.size();
+        int inputBufferCount = 0;
+        int outFrameCount = 0;
+        YUVValue expected = new YUVValue();
+        YUVValue decoded = new YUVValue();
+        long lastOutputTimeNs = 0;
+        long start = System.currentTimeMillis();
+        while (!sawOutputEOS) {
+            if (inputLeft > 0) {
+                int inputBufIndex = codec.dequeueInputBuffer(VIDEO_CODEC_WAIT_TIME_US);
+
+                if (inputBufIndex >= 0) {
+                    ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
+                    dstBuf.clear();
+                    ByteBuffer src = mEncodedOutputBuffer.get(inputBufferCount).first;
+                    BufferInfo srcInfo = mEncodedOutputBuffer.get(inputBufferCount).second;
+                    int writeSize = src.capacity();
+                    dstBuf.put(src.array(), 0, writeSize);
+
+                    int flags = srcInfo.flags;
+                    if ((System.currentTimeMillis() - start) > mTestConfig.mMaxTimeMs) {
+                        flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+                    }
+
+                    codec.queueInputBuffer(
+                            inputBufIndex,
+                            0 /* offset */,
+                            writeSize,
+                            srcInfo.presentationTimeUs,
+                            flags);
+                    inputLeft --;
+                    inputBufferCount ++;
+                }
+            }
+
+            int res = codec.dequeueOutputBuffer(info, VIDEO_CODEC_WAIT_TIME_US);
+            if (res >= 0) {
+                int outputBufIndex = res;
+
+                // only do YUV compare on EOS frame if the buffer size is none-zero
+                if (info.size > 0) {
+                    if (lastOutputTimeNs > 0) {
+                        int pos = outFrameCount - 1;
+                        if (pos < mDecoderFrameTimeDiff[mCurrentTestRound].length) {
+                            long diff = System.nanoTime() - lastOutputTimeNs;
+                            mDecoderFrameTimeDiff[mCurrentTestRound][pos] = diff;
+                        }
+                    }
+                    lastOutputTimeNs = System.nanoTime();
+
+                    if (mTestConfig.mTestPixels) {
+                        Point origin = getOrigin(outFrameCount);
+                        int i;
+
+                        // if decoder supports planar or semiplanar, check output with
+                        // ByteBuffer & Image each on half of the points
+                        int pixelCheckPerFrame = PIXEL_CHECK_PER_FRAME;
+                        if (!isDstFlexYUV()) {
+                            pixelCheckPerFrame /= 2;
+                            ByteBuffer buf = codec.getOutputBuffer(outputBufIndex);
+                            if (VERBOSE && (outFrameCount == 0)) {
+                                printByteBuffer("Y ", buf, 0, 20);
+                                printByteBuffer("UV ", buf, mVideoWidth * mVideoHeight, 20);
+                                printByteBuffer("UV ", buf,
+                                        mVideoWidth * mVideoHeight + mVideoWidth * 60, 20);
+                            }
+                            for (i = 0; i < pixelCheckPerFrame; i++) {
+                                int w = mRandom.nextInt(mVideoWidth);
+                                int h = mRandom.nextInt(mVideoHeight);
+                                getPixelValuesFromYUVBuffers(origin.x, origin.y, w, h, expected);
+                                getPixelValuesFromOutputBuffer(buf, w, h, decoded);
+                                if (VERBOSE) {
+                                    Log.i(TAG, outFrameCount + "-" + i + "- th round: ByteBuffer:"
+                                            + " expected "
+                                            + expected.mY + "," + expected.mU + "," + expected.mV
+                                            + " decoded "
+                                            + decoded.mY + "," + decoded.mU + "," + decoded.mV);
+                                }
+                                totalErrorSquared += expected.calcErrorSquared(decoded);
+                            }
+                        }
+
+                        Image image = codec.getOutputImage(outputBufIndex);
+                        assertTrue(image != null);
+                        for (i = 0; i < pixelCheckPerFrame; i++) {
+                            int w = mRandom.nextInt(mVideoWidth);
+                            int h = mRandom.nextInt(mVideoHeight);
+                            getPixelValuesFromYUVBuffers(origin.x, origin.y, w, h, expected);
+                            getPixelValuesFromImage(image, w, h, decoded);
+                            if (VERBOSE) {
+                                Log.i(TAG, outFrameCount + "-" + i + "- th round: FlexYUV:"
+                                        + " expcted "
+                                        + expected.mY + "," + expected.mU + "," + expected.mV
+                                        + " decoded "
+                                        + decoded.mY + "," + decoded.mU + "," + decoded.mV);
+                            }
+                            totalErrorSquared += expected.calcErrorSquared(decoded);
+                        }
+                    }
+                    outFrameCount++;
+                }
+                codec.releaseOutputBuffer(outputBufIndex, false /* render */);
+                if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                    Log.d(TAG, "saw output EOS.");
+                    sawOutputEOS = true;
+                }
+            } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                mDecOutputFormat = codec.getOutputFormat();
+                Log.d(TAG, "output format has changed to " + mDecOutputFormat);
+                int colorFormat = mDecOutputFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
+                if (colorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar
+                        || colorFormat == CodecCapabilities.COLOR_FormatYUV420Planar) {
+                    mDstColorFormat = colorFormat;
+                } else {
+                    mDstColorFormat = CodecCapabilities.COLOR_FormatYUV420Flexible;
+                    Log.w(TAG, "output format changed to unsupported one " +
+                            Integer.toHexString(colorFormat) + ", using FlexYUV");
+                }
+            }
+        }
+        long finish = System.currentTimeMillis();
+        int validDataNum = Math.min(outFrameCount - 1,
+                mDecoderFrameTimeDiff[mCurrentTestRound].length);
+        mDecoderFrameTimeDiff[mCurrentTestRound] =
+                Arrays.copyOf(mDecoderFrameTimeDiff[mCurrentTestRound], validDataNum);
+        codec.stop();
+        codec.release();
+        codec = null;
+
+        // divide by 3 as sum is done for Y, U, V.
+        double errorRms = Math.sqrt(totalErrorSquared / PIXEL_CHECK_PER_FRAME / outFrameCount / 3);
+        double[] result = { (double) finish - start, errorRms };
+        return result;
+    }
+
+    /**
+     *  returns origin in the absolute frame for given frame count.
+     *  The video scene is moving by moving origin per each frame.
+     */
+    private Point getOrigin(int frameCount) {
+        if (frameCount < 100) {
+            return new Point(2 * frameCount, 0);
+        } else if (frameCount < 200) {
+            return new Point(200, (frameCount - 100) * 2);
+        } else {
+            if (frameCount > 300) { // for safety
+                frameCount = 300;
+            }
+            return new Point(600 - frameCount * 2, 600 - frameCount * 2);
+        }
+    }
+
+    /**
+     * initialize reference YUV plane
+     * @param w This should be YUV_PLANE_ADDITIONAL_LENGTH pixels bigger than video resolution
+     *          to allow movements
+     * @param h This should be YUV_PLANE_ADDITIONAL_LENGTH pixels bigger than video resolution
+     *          to allow movements
+     * @param semiPlanarEnc
+     * @param semiPlanarDec
+     */
+    private void initYUVPlane(int w, int h) {
+        int bufferSizeY = w * h;
+        mYBuffer = ByteBuffer.allocate(bufferSizeY);
+        mUVBuffer = ByteBuffer.allocate(bufferSizeY / 2);
+        mYDirectBuffer = ByteBuffer.allocateDirect(bufferSizeY);
+        mUVDirectBuffer = ByteBuffer.allocateDirect(bufferSizeY / 2);
+        mBufferWidth = w;
+        mBufferHeight = h;
+        final byte[] yArray = mYBuffer.array();
+        final byte[] uvArray = mUVBuffer.array();
+        for (int i = 0; i < h; i++) {
+            for (int j = 0; j < w; j++) {
+                yArray[i * w + j]  = clampY((i + j) & 0xff);
+            }
+        }
+        if (isSrcSemiPlanar()) {
+            for (int i = 0; i < h/2; i++) {
+                for (int j = 0; j < w/2; j++) {
+                    uvArray[i * w + 2 * j]  = (byte) (i & 0xff);
+                    uvArray[i * w + 2 * j + 1]  = (byte) (j & 0xff);
+                }
+            }
+        } else { // planar, U first, then V
+            int vOffset = bufferSizeY / 4;
+            for (int i = 0; i < h/2; i++) {
+                for (int j = 0; j < w/2; j++) {
+                    uvArray[i * w/2 + j]  = (byte) (i & 0xff);
+                    uvArray[i * w/2 + vOffset + j]  = (byte) (j & 0xff);
+                }
+            }
+        }
+        mYDirectBuffer.put(yArray);
+        mUVDirectBuffer.put(uvArray);
+        mYDirectBuffer.rewind();
+        mUVDirectBuffer.rewind();
+    }
+
+    /**
+     * class to store pixel values in YUV
+     *
+     */
+    public class YUVValue {
+        public byte mY;
+        public byte mU;
+        public byte mV;
+        public YUVValue() {
+        }
+
+        public boolean equalTo(YUVValue other) {
+            return (mY == other.mY) && (mU == other.mU) && (mV == other.mV);
+        }
+
+        public double calcErrorSquared(YUVValue other) {
+            // Java's byte is signed but here we want to calculate difference in unsigned bytes.
+            double yDelta = (mY & 0xFF) - (other.mY & 0xFF);
+            double uDelta = (mU & 0xFF) - (other.mU & 0xFF);
+            double vDelta = (mV & 0xFF) - (other.mV & 0xFF);
+            return yDelta * yDelta + uDelta * uDelta + vDelta * vDelta;
+        }
+    }
+
+    /**
+     * Read YUV values from given position (x,y) for given origin (originX, originY)
+     * The whole data is already available from YBuffer and UVBuffer.
+     * @param result pass the result via this. This is for avoiding creating / destroying too many
+     *               instances
+     */
+    private void getPixelValuesFromYUVBuffers(int originX, int originY, int x, int y,
+            YUVValue result) {
+        result.mY = mYBuffer.get((originY + y) * mBufferWidth + (originX + x));
+        if (isSrcSemiPlanar()) {
+            int index = (originY + y) / 2 * mBufferWidth + (originX + x) / 2 * 2;
+            //Log.d(TAG, "YUV " + originX + "," + originY + "," + x + "," + y + "," + index);
+            result.mU = mUVBuffer.get(index);
+            result.mV = mUVBuffer.get(index + 1);
+        } else {
+            int vOffset = mBufferWidth * mBufferHeight / 4;
+            int index = (originY + y) / 2 * mBufferWidth / 2 + (originX + x) / 2;
+            result.mU = mUVBuffer.get(index);
+            result.mV = mUVBuffer.get(vOffset + index);
+        }
+    }
+
+    /**
+     * Read YUV pixels from decoded output buffer for give (x, y) position
+     * Output buffer is composed of Y parts followed by U/V
+     * @param result pass the result via this. This is for avoiding creating / destroying too many
+     *               instances
+     */
+    private void getPixelValuesFromOutputBuffer(ByteBuffer buffer, int x, int y, YUVValue result) {
+        result.mY = buffer.get(y * mVideoWidth + x);
+        if (isDstSemiPlanar()) {
+            int index = mVideoWidth * mVideoHeight + y / 2 * mVideoWidth + x / 2 * 2;
+            //Log.d(TAG, "Decoded " + x + "," + y + "," + index);
+            result.mU = buffer.get(index);
+            result.mV = buffer.get(index + 1);
+        } else {
+            int vOffset = mVideoWidth * mVideoHeight / 4;
+            int index = mVideoWidth * mVideoHeight + y / 2 * mVideoWidth / 2 + x / 2;
+            result.mU = buffer.get(index);
+            result.mV = buffer.get(index + vOffset);
+        }
+    }
+
+    private void getPixelValuesFromImage(Image image, int x, int y, YUVValue result) {
+        assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
+
+        Plane[] planes = image.getPlanes();
+        assertTrue(planes.length == 3);
+
+        result.mY = getPixelFromPlane(planes[0], x, y);
+        result.mU = getPixelFromPlane(planes[1], x / 2, y / 2);
+        result.mV = getPixelFromPlane(planes[2], x / 2, y / 2);
+    }
+
+    private byte getPixelFromPlane(Plane plane, int x, int y) {
+        ByteBuffer buf = plane.getBuffer();
+        return buf.get(y * plane.getRowStride() + x * plane.getPixelStride());
+    }
+
+    /**
+     * Y cannot have full range. clamp it to prevent invalid value.
+     */
+    private byte clampY(int y) {
+        if (y < Y_CLAMP_MIN) {
+            y = Y_CLAMP_MIN;
+        } else if (y > Y_CLAMP_MAX) {
+            y = Y_CLAMP_MAX;
+        }
+        return (byte) (y & 0xff);
+    }
+
+    // for debugging
+    private void printByteArray(String msg, byte[] data, int offset, int len) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(msg);
+        builder.append(":");
+        for (int i = offset; i < offset + len; i++) {
+            builder.append(Integer.toHexString(data[i]));
+            builder.append(",");
+        }
+        builder.deleteCharAt(builder.length() - 1);
+        Log.i(TAG, builder.toString());
+    }
+
+    // for debugging
+    private void printByteBuffer(String msg, ByteBuffer data, int offset, int len) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(msg);
+        builder.append(":");
+        for (int i = offset; i < offset + len; i++) {
+            builder.append(Integer.toHexString(data.get(i)));
+            builder.append(",");
+        }
+        builder.deleteCharAt(builder.length() - 1);
+        Log.i(TAG, builder.toString());
+    }
+
+    /**
+     * Generates the presentation time for frame N, in microseconds.
+     */
+    private long computePresentationTime(int frameIndex) {
+        return 132 + frameIndex * 1000000L / mFrameRate;
+    }
+}
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index 5f2b223..d479d9f 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -18,11 +18,17 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+DEVICE_INFO_MIN_SDK := 23
+DEVICE_INFO_TARGET_SDK := 23
+
 DEVICE_INFO_PERMISSIONS :=
 
-DEVICE_INFO_ACTIVITIES :=
+DEVICE_INFO_ACTIVITIES := \
+    com.android.compatibility.common.deviceinfo.GlesStubActivity
 
 LOCAL_PACKAGE_NAME := CtsDeviceInfo
 
-include $(BUILD_CTS_DEVICE_INFO_PACKAGE)
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
 
+include $(BUILD_CTS_DEVICE_INFO_PACKAGE)
diff --git a/tools/cts-device-info/src/com/android/cts/deviceinfo/SampleDeviceInfo.java b/tools/cts-device-info/src/com/android/cts/deviceinfo/SampleDeviceInfo.java
index 886193c..a645585 100644
--- a/tools/cts-device-info/src/com/android/cts/deviceinfo/SampleDeviceInfo.java
+++ b/tools/cts-device-info/src/com/android/cts/deviceinfo/SampleDeviceInfo.java
@@ -17,17 +17,12 @@
 
 import android.os.Bundle;
 
-import com.android.compatibility.common.deviceinfo.DeviceInfoActivity;
+import com.android.compatibility.common.deviceinfo.DeviceInfo;
 
 /**
  * Sample device info collector.
  */
-public class SampleDeviceInfo extends DeviceInfoActivity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
+public class SampleDeviceInfo extends DeviceInfo {
 
     @Override
     protected void collectDeviceInfo() {
@@ -60,4 +55,3 @@
         endGroup(); // foo
     }
 }
-
diff --git a/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java b/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java
index 78d4249..1b48ddf 100644
--- a/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java
+++ b/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java
@@ -65,6 +65,10 @@
 
     static final String JUNIT_TEST_CASE_CLASS_NAME = "junit.framework.testcase";
 
+    private static final String TIMEOUT_ANNOTATION = "com.android.cts.util.TimeoutReq";
+    private static final String SUPPRESS_ANNOTATION =
+            "android.test.suitebuilder.annotation.Suppress";
+
     public static boolean start(RootDoc root) {
         ClassDoc[] classes = root.classes();
         if (classes == null) {
@@ -93,10 +97,11 @@
                             continue;
                         }
 
+                        boolean suppressed = false;
                         AnnotationDesc[] annotations = method.annotations();
                         for (AnnotationDesc annot : annotations) {
                             String atype = annot.annotationType().toString();
-                            if (atype.equals("com.android.cts.util.TimeoutReq")) {
+                            if (atype.equals(TIMEOUT_ANNOTATION)) {
                                 ElementValuePair[] cpairs = annot.elementValues();
                                 for (ElementValuePair pair : cpairs) {
                                     AnnotationTypeElementDoc elem = pair.element();
@@ -105,8 +110,13 @@
                                         timeout = ((Integer) value.value());
                                     }
                                 }
+                            } else if (atype.equals(SUPPRESS_ANNOTATION)) {
+                                suppressed = true;
                             }
                         }
+                        if (suppressed) {
+                            continue;
+                        }
                     } else {
                         /* JUnit4 */
                         boolean isTest = false;
diff --git a/tools/cts-preconditions/Android.mk b/tools/cts-preconditions/Android.mk
new file mode 100644
index 0000000..daf35f4
--- /dev/null
+++ b/tools/cts-preconditions/Android.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-preconditions
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_PACKAGE_NAME := CtsPreconditions
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tools/cts-preconditions/AndroidManifest.xml b/tools/cts-preconditions/AndroidManifest.xml
new file mode 100644
index 0000000..a8eb827
--- /dev/null
+++ b/tools/cts-preconditions/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.preconditions.cts">
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:label="CTS preconditions test"
+        android:targetPackage="com.android.preconditions.cts" >
+    </instrumentation>
+</manifest>
diff --git a/tools/cts-preconditions/src/com/android/preconditions/cts/PreconditionsTest.java b/tools/cts-preconditions/src/com/android/preconditions/cts/PreconditionsTest.java
new file mode 100644
index 0000000..b3162b9
--- /dev/null
+++ b/tools/cts-preconditions/src/com/android/preconditions/cts/PreconditionsTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 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.preconditions.cts;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+import com.android.compatibility.common.preconditions.ExternalStorageHelper;
+import com.android.compatibility.common.preconditions.ScreenLockHelper;
+
+/**
+ * A test to verify that device-side preconditions are met for CTS
+ */
+public class PreconditionsTest extends AndroidTestCase {
+
+    /**
+     * Test if device has no screen lock
+     * @throws Exception
+     */
+    public void testScreenUnlocked() throws Exception {
+        assertFalse("Device must have screen lock disabled",
+                ScreenLockHelper.isDeviceSecure(this.getContext()));
+    }
+
+    /**
+     * Test if device has accessible external storage
+     * @throws Exception
+     */
+    public void testExternalStoragePresent() throws Exception {
+        assertTrue("Device must have external storage mounted in order to run CTS",
+                ExternalStorageHelper.isExternalStorageReadable());
+        assertTrue("Device external storage must be writable in order to run CTS",
+                ExternalStorageHelper.isExternalStorageWritable());
+    }
+
+}
diff --git a/tools/cts-tradefed/Android.mk b/tools/cts-tradefed/Android.mk
new file mode 100644
index 0000000..2f743e6
--- /dev/null
+++ b/tools/cts-tradefed/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, ../../common/host-side/tradefed/src)
+
+LOCAL_JAVA_RESOURCE_DIRS := res
+LOCAL_JAVA_RESOURCE_DIRS += ../../common/host-side/tradefed/res
+
+LOCAL_SUITE_BUILD_NUMBER := $(BUILD_NUMBER)
+LOCAL_SUITE_NAME := CTS_V2
+LOCAL_SUITE_FULLNAME := "Compatibility Test Suite"
+LOCAL_SUITE_VERSION := 5.0
+
+LOCAL_MODULE := cts-tradefed_v2
+
+include $(BUILD_COMPATIBILITY_SUITE)
+
+# Build all sub-directories
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/cts-tradefed/DynamicConfig.xml b/tools/cts-tradefed/DynamicConfig.xml
new file mode 100644
index 0000000..b675082
--- /dev/null
+++ b/tools/cts-tradefed/DynamicConfig.xml
@@ -0,0 +1,17 @@
+<!-- Copyright (C) 2015 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.
+-->
+
+<DynamicConfig>
+</DynamicConfig>
diff --git a/tools/cts-tradefed/README b/tools/cts-tradefed/README
new file mode 100644
index 0000000..d1357aa
--- /dev/null
+++ b/tools/cts-tradefed/README
@@ -0,0 +1,83 @@
+CTS Trade Federation
+---------------------
+
+CTS Trade Federation, cts-tradefed for short, is the next
+generation test harness for CTS.
+
+cts-tradefed is built on top of the Android Trade Federation test harness.
+
+It works in a similar manner to the prior CTS harness, but supports some
+advanced features such as:
+
+  - modular, flexible extensible design. cts-tradefed can be extended to
+support running CTS in a continuous test environment.
+  - supports sharding a CTS test run across multiple devices in parallel
+  - automatically continue a CTS test run on another device if connection
+is lost
+
+Configuring cts-tradefed
+------------------------
+
+1. Ensure 'adb' is in your current PATH. adb can be found in the
+Android SDK available from http://developer.android.com
+
+Example:
+  PATH=$PATH:/home/myuser/android-sdk-linux_x86/platform-tools
+
+2. Follow the 'Setting up your device' steps documented in the
+CTS User Manual. The CTS User Manual can be downloaded at
+http://source.android.com/compatibility/downloads.html
+
+3. Connect the device to the host machine.
+
+4. Ensure device is visible via 'adb devices'
+
+Using cts-tradefed
+-------------------
+
+To run a test plan on a single device:
+
+1. Make sure you have at least one device connected
+2. Launch the cts-tradefed console by running the 'cts-tradefed'. If you've
+downloaded and extracted the CTS zip, the script can be found at
+  android-cts/tools/cts-tradefed
+Or else if you are working from the Android source tree and have run make cts,
+the script can be found at
+  out/host/linux-x86/cts/android-cts/tools/cts-tradefed
+3. Type:
+'run cts' to run the default CTS plan
+
+Some other useful commands are
+
+To run a test module:
+'run cts --module <module_name>'
+
+To run a specific test:
+'run cts --test <test_name>'
+
+To shard a plan test run on multiple devices
+'run cts --shards <number of shards>
+note: all connected devices must be running the same build
+
+For more options:
+'run cts --help'
+
+CTS Tradefed Development
+------------------------
+See http://source.android.com for instructions on obtaining the Android
+platform source code and setting up a build environment.
+
+The source for the CTS extensions for tradefed can be found at
+<android source root>/cts/tools/tradefed-host
+
+The source for the tradefed framework can be found on the 'tradefed' branch.
+
+Perform these steps to build and run cts-tradefed from the development
+environment:
+cd <path to android source root>
+make cts
+cts-tradefed
+
+More documentation and details on using and extending trade federation will
+be forthcoming in the near future.
+
diff --git a/tools/cts-tradefed/etc/Android.mk b/tools/cts-tradefed/etc/Android.mk
new file mode 100644
index 0000000..877f67c
--- /dev/null
+++ b/tools/cts-tradefed/etc/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PREBUILT_EXECUTABLES := cts-tradefed_v2
+include $(BUILD_HOST_PREBUILT)
+
diff --git a/tools/cts-tradefed/etc/cts-tradefed_v2 b/tools/cts-tradefed/etc/cts-tradefed_v2
new file mode 100755
index 0000000..d1cf0cc
--- /dev/null
+++ b/tools/cts-tradefed/etc/cts-tradefed_v2
@@ -0,0 +1,119 @@
+#!/bin/bash
+
+# Copyright (C) 2015 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.
+
+# launcher script for cts-tradefed harness
+# can be used from an Android build environment, or a standalone cts zip
+
+checkFile() {
+    if [ ! -f "$1" ]; then
+        echo "Unable to locate $1"
+        exit
+    fi;
+}
+
+checkPath() {
+    if ! type -P $1 &> /dev/null; then
+        echo "Unable to find $1 in path."
+        exit
+    fi;
+}
+
+checkPath adb
+checkPath java
+
+# check java version
+JAVA_VERSION=$(java -version 2>&1 | head -n 2 | grep '[ "]1\.[678][\. "$$]')
+if [ "${JAVA_VERSION}" == "" ]; then
+    echo "Wrong java version. 1.6, 1.7 or 1.8 is required."
+    exit
+fi
+
+# check debug flag and set up remote debugging
+if [ -n "${TF_DEBUG}" ]; then
+  if [ -z "${TF_DEBUG_PORT}" ]; then
+    TF_DEBUG_PORT=10088
+  fi
+  RDBG_FLAG=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=${TF_DEBUG_PORT}
+fi
+
+# get OS
+HOST=`uname`
+if [ "$HOST" == "Linux" ]; then
+    OS="linux-x86"
+elif [ "$HOST" == "Darwin" ]; then
+    OS="darwin-x86"
+else
+    echo "Unrecognized OS"
+    exit
+fi
+
+# check if in Android build env
+if [ ! -z "${ANDROID_BUILD_TOP}" ]; then
+    if [ ! -z "${ANDROID_HOST_OUT}" ]; then
+      CTS_V2_ROOT=${ANDROID_HOST_OUT}/cts_v2
+    else
+      CTS_V2_ROOT=${ANDROID_BUILD_TOP}/${OUT_DIR:-out}/host/${OS}/cts_v2
+    fi
+    if [ ! -d ${CTS_V2_ROOT} ]; then
+        echo "Could not find $CTS_V2_ROOT in Android build environment. Try 'make cts_v2'"
+        exit
+    fi;
+fi;
+
+if [ -z ${CTS_V2_ROOT} ]; then
+    # assume we're in an extracted cts install
+    CTS_V2_ROOT="$(dirname $0)/../.."
+fi;
+
+JAR_DIR=${CTS_V2_ROOT}/android-cts_v2/tools
+JARS="tradefed-prebuilt
+  hosttestlib
+  compatibility-host-util
+  cts-tradefed_v2"
+
+for JAR in $JARS; do
+    checkFile ${JAR_DIR}/${JAR}.jar
+    JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
+done
+
+OPTIONAL_JARS="
+  google-tradefed
+  google-tradefed-tests
+  google-tf-prod-tests"
+
+for JAR in $OPTIONAL_JARS; do
+    if [ -f "$JAR.jar" ]; then
+        JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
+    fi;
+done
+
+# load any shared libraries for host-side executables
+LIB_DIR=${CTS_V2_ROOT}/android-cts_v2/lib
+if [ "$HOST" == "Linux" ]; then
+    LD_LIBRARY_PATH=${LIB_DIR}:${LIB_DIR}64:${LD_LIBRARY_PATH}
+    export LD_LIBRARY_PATH
+elif [ "$HOST" == "Darwin" ]; then
+    DYLD_LIBRARY_PATH=${LIB_DIR}:${LIB_DIR}64:${DYLD_LIBRARY_PATH}
+    export DYLD_LIBRARY_PATH
+fi
+
+# include any host-side test jars
+for j in ${CTS_V2_ROOT}/android-cts_v2/testcases/*.jar; do
+    JAR_PATH=${JAR_PATH}:$j
+done
+
+java $RDBG_FLAG -cp ${JAR_PATH} -DCTS_V2_ROOT=${CTS_V2_ROOT} com.android.compatibility.common.tradefed.command.CompatibilityConsole "$@"
+
diff --git a/tools/cts-tradefed/res/config/cts-camera.xml b/tools/cts-tradefed/res/config/cts-camera.xml
new file mode 100644
index 0000000..5bc395d
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-camera.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs CTS-camera from a pre-existing CTS installation">
+
+    <include name="cts" />
+
+    <option name="compatibility:plan" value="cts-camera" />
+
+    <!-- All camera CTS tests -->
+    <option name="compatibility:include-filter" value="CtsCameraTestCases" />
+
+    <!-- Other camera related CTS tests -->
+    <option name="compatibility:include-filter"
+        value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testCameraFeatures"/>
+    <option name="compatibility:include-filter"
+        value="CtsPermissionTestCases android.permission.cts.CameraPermissionTest"/>
+    <option name="compatibility:include-filter"
+        value="CtsPermissionTestCases android.permission.cts.Camera2PermissionTest"/>
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-filtered-sample.xml b/tools/cts-tradefed/res/config/cts-filtered-sample.xml
new file mode 100644
index 0000000..73b98c5
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-filtered-sample.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs CTS from a pre-existing CTS installation">
+
+    <include name="common-compatibility-config" />
+
+    <option name="compatibility:plan" value="cts-filtered-sample" />
+
+    <!-- Tell all AndroidJUnitTests to only run the medium sized tests -->
+    <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:size:medium" />
+
+    <!-- Tell 64bit CtsContentTestCases which timeout to use -->
+    <option name="compatibility:module-arg" value="arm64-v8a CtsContentTestCases:test-timeout:600" />
+
+    <!-- Include CtsGestureTestCases but only run the tests on arm32 -->
+    <option name="compatibility:include-filter" value="armeabi-v7a CtsGestureTestCases" />
+
+    <!-- Exclude CtsMediaStressTestCases -->
+    <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases" />
+
+    <!-- Include CtsUtilTestCases but only run the small tests -->
+    <option name="compatibility:module-arg" value="CtsUtilTestCases:size:small" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts.xml b/tools/cts-tradefed/res/config/cts.xml
new file mode 100644
index 0000000..87e678b
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs CTS from a pre-existing CTS installation">
+
+    <include name="everything" />
+
+    <option name="compatibility:plan" value="cts" />
+
+    <option name="enable-root" value="false" />
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.StayAwakePreparer" />
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
+        <option name="property-name" value="ro.build.type" />
+        <option name="expected-value" value="user"/> <!-- Device should have user build -->
+        <option name="throw-error" value="false"/> <!-- Only print warning if not user build -->
+    </target_preparer>
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
+        <option name="property-name" value="ro.product.locale" />
+        <option name="expected-value" value="en-US"/> <!-- Device locale should be US English -->
+        <option name="throw-error" value="false"/> <!-- Only print warning if not en-US -->
+    </target_preparer>
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkPreconditionCheck">
+        <option name="apk" value="CtsPreconditions.apk"/>
+        <option name="package" value="com.android.preconditions.cts"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="rm -rf /sdcard/device-info-files" />
+    </target_preparer>
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DeviceInfoCollector">
+        <option name="apk" value="CtsDeviceInfo.apk"/>
+        <option name="package" value="com.android.compatibility.common.deviceinfo"/>
+        <option name="src-dir" value="/sdcard/device-info-files/"/>
+        <option name="dest-dir" value="device-info-files/"/>
+    </target_preparer>
+
+</configuration>
diff --git a/tools/cts-tradefed/tests/Android.mk b/tools/cts-tradefed/tests/Android.mk
new file mode 100644
index 0000000..7314fdb
--- /dev/null
+++ b/tools/cts-tradefed/tests/Android.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := cts-tradefed-tests_v2
+LOCAL_MODULE_TAGS := optional
+LOCAL_JAVA_LIBRARIES := tradefed-prebuilt cts-tradefed_v2
+
+include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/tools/cts-tradefed/tests/run_tests.sh b/tools/cts-tradefed/tests/run_tests.sh
new file mode 100755
index 0000000..6a96928
--- /dev/null
+++ b/tools/cts-tradefed/tests/run_tests.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright (C) 2015 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.
+
+# Helper script for running unit tests for compatibility libraries
+
+CTS_DIR=$(dirname ${0})/../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+    compatibility-common-util-hostsidelib\
+    compatibility-host-util\
+    cts-tradefed-tests_v2\
+    cts-tradefed_v2"
+
+run_tests "com.android.compatibility.tradefed.CtsTradefedTest" "${JARS}" "${@}"
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java b/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java
new file mode 100644
index 0000000..6469a01
--- /dev/null
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.tradefed;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.util.FileUtil;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+
+/**
+ * Tests for cts-tradefed.
+ */
+public class CtsTradefedTest extends TestCase {
+
+    private static final String PROPERTY_NAME = "CTS_V2_ROOT";
+    private static final String SUITE_FULL_NAME = "Compatibility Test Suite";
+    private static final String SUITE_NAME = "CTS_V2";
+    private static final String SUITE_PLAN = "cts";
+    private static final String DYNAMIC_CONFIG_URL = "";
+
+    public void testSuiteInfoLoad() throws Exception {
+        // Test the values in the manifest can be loaded
+        File root = FileUtil.createTempDir("root");
+        System.setProperty(PROPERTY_NAME, root.getAbsolutePath());
+        File base = new File(root, "android-cts_v2");
+        base.mkdirs();
+        File tests = new File(base, "testcases");
+        tests.mkdirs();
+        CompatibilityBuildProvider provider = new CompatibilityBuildProvider();
+        IBuildInfo info = provider.getBuild();
+        CompatibilityBuildHelper helper = new CompatibilityBuildHelper(info);
+        helper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL);
+        assertEquals("Incorrect suite full name", SUITE_FULL_NAME, helper.getSuiteFullName());
+        assertEquals("Incorrect suite name", SUITE_NAME, helper.getSuiteName());
+        FileUtil.recursiveDelete(root);
+        System.clearProperty(PROPERTY_NAME);
+    }
+}
diff --git a/tools/cts-xml-generator/src/Android.mk b/tools/cts-xml-generator/src/Android.mk
index a6d85b6..94c561b 100644
--- a/tools/cts-xml-generator/src/Android.mk
+++ b/tools/cts-xml-generator/src/Android.mk
@@ -18,15 +18,13 @@
 # ============================================================
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := \
-    $(call all-subdir-java-files) \
-    ../../../libs/commonutil/src/com/android/cts/util/AbiUtils.java
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_JAR_MANIFEST := MANIFEST.mf
 
 LOCAL_MODULE := cts-xml-generator
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib
+LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib compatibility-host-util
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java
index ed09b8e..c680c2a 100644
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java
@@ -46,4 +46,8 @@
     public int compareTo(TestCase another) {
         return getName().compareTo(another.getName());
     }
+
+    public int countTests() {
+        return mTests.size();
+    }
 }
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java
index 466f8d7..1d71e1f 100644
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java
@@ -66,4 +66,15 @@
     public int compareTo(TestSuite another) {
         return getName().compareTo(another.getName());
     }
+
+    public int countTests() {
+        int count = 0;
+        for (TestSuite suite : mSuites.values()) {
+            count += suite.countTests();
+        }
+        for (TestCase testCase : mCases) {
+            count += testCase.countTests();
+        }
+        return count;
+    }
 }
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
index 328b855..f139053 100644
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
@@ -16,12 +16,12 @@
 
 package com.android.cts.xmlgenerator;
 
-import com.android.cts.util.AbiUtils;
-
 import vogar.Expectation;
 import vogar.ExpectationStore;
 import vogar.Result;
 
+import com.android.compatibility.common.util.AbiUtils;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -166,6 +166,9 @@
             StringBuilder nameCollector) {
         Collection<TestSuite> sorted = sortCollection(suites);
         for (TestSuite suite : sorted) {
+            if (suite.countTests() == 0) {
+                continue;
+            }
             writer.append("<TestSuite name=\"").append(suite.getName()).println("\">");
 
             String namePart = suite.getName();
@@ -187,6 +190,9 @@
             StringBuilder nameCollector) {
         Collection<TestCase> sorted = sortCollection(cases);
         for (TestCase testCase : sorted) {
+            if (testCase.countTests() == 0) {
+                continue;
+            }
             String name = testCase.getName();
             writer.append("<TestCase name=\"").append(name).println("\">");
             nameCollector.append('.').append(name);
@@ -259,7 +265,7 @@
         String[] unsupportedAbis = description.split(":")[1].split(",");
         for (String a : unsupportedAbis) {
             String abi = a.trim();
-            if (!AbiUtils.isAbiSupportedByCts(abi)) {
+            if (!AbiUtils.isAbiSupportedByCompatibility(abi)) {
                 throw new RuntimeException(
                         String.format("Unrecognised ABI %s in %s", abi, description));
             }
diff --git a/tools/tradefed-host/.classpath b/tools/tradefed-host/.classpath
index dbeeb01..e716219 100644
--- a/tools/tradefed-host/.classpath
+++ b/tools/tradefed-host/.classpath
@@ -7,6 +7,5 @@
 	<classpathentry exported="true" kind="var" path="CTS_SRC_ROOT/out/host/common/obj/JAVA_LIBRARIES/ctsdeviceinfolib_intermediates/javalib.jar"/>
 	<classpathentry kind="var" path="CTS_SRC_ROOT/out/host/common/obj/JAVA_LIBRARIES/hosttestlib_intermediates/javalib.jar"/>
 	<classpathentry kind="var" path="CTS_SRC_ROOT/prebuilts/misc/common/tradefed/tradefed-prebuilt.jar"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/cts-commonutil"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/tools/tradefed-host/Android.mk b/tools/tradefed-host/Android.mk
index 1f73e95..c33a927 100644
--- a/tools/tradefed-host/Android.mk
+++ b/tools/tradefed-host/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_MODULE := cts-tradefed
 LOCAL_MODULE_TAGS := optional
 LOCAL_JAVA_LIBRARIES := tradefed-prebuilt hosttestlib
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceinfolib
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceinfolib compatibility-host-util
 
 LOCAL_JAR_MANIFEST := MANIFEST.mf
 
diff --git a/tools/tradefed-host/res/config/basic-reporters.xml b/tools/tradefed-host/res/config/basic-reporters.xml
new file mode 100644
index 0000000..d52a85b
--- /dev/null
+++ b/tools/tradefed-host/res/config/basic-reporters.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration with basic cts reporters" >
+    <result_reporter class="com.android.cts.tradefed.result.CtsTestLogReporter" />
+    <result_reporter class="com.android.cts.tradefed.result.IssueReporter" />
+</configuration>
diff --git a/tools/tradefed-host/res/config/cts.xml b/tools/tradefed-host/res/config/cts.xml
index 416b400..794605c 100644
--- a/tools/tradefed-host/res/config/cts.xml
+++ b/tools/tradefed-host/res/config/cts.xml
@@ -22,7 +22,5 @@
     <test class="com.android.cts.tradefed.testtype.CtsTest" />
     <logger class="com.android.tradefed.log.FileLogger" />
     <result_reporter class="com.android.cts.tradefed.result.CtsXmlResultReporter" />
-    <result_reporter class="com.android.cts.tradefed.result.CtsTestLogReporter" />
-    <result_reporter class="com.android.cts.tradefed.result.IssueReporter" />
-
+    <template-include name="reporters" default="basic-reporters" />
 </configuration>
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
index 66a4562..ca67746 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
@@ -31,7 +31,7 @@
     @Option(name="cts-install-path", description="the path to the cts installation to use")
     private String mCtsRootDirPath = System.getProperty("CTS_ROOT");
 
-    public static final String CTS_BUILD_VERSION = "6.0_r3";
+    public static final String CTS_BUILD_VERSION = "5.0_r1.91";
     public static final String CTS_PACKAGE = "com.android.cts.tradefed.testtype";
 
     /**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/command/CtsConsole.java b/tools/tradefed-host/src/com/android/cts/tradefed/command/CtsConsole.java
index 24239e6..4cb9e16 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/command/CtsConsole.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/command/CtsConsole.java
@@ -15,6 +15,7 @@
  */
 package com.android.cts.tradefed.command;
 
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.build.CtsBuildHelper;
 import com.android.cts.tradefed.build.CtsBuildProvider;
 import com.android.cts.tradefed.result.ITestResultRepo;
@@ -23,7 +24,6 @@
 import com.android.cts.tradefed.result.TestResultRepo;
 import com.android.cts.tradefed.testtype.ITestPackageRepo;
 import com.android.cts.tradefed.testtype.TestPackageRepo;
-import com.android.cts.util.AbiUtils;
 import com.android.tradefed.build.IFolderBuildInfo;
 import com.android.tradefed.command.Console;
 import com.android.tradefed.config.ArgsOptionParser;
@@ -120,7 +120,7 @@
                 CtsBuildHelper ctsBuild = getCtsBuildHelper();
                 if (ctsBuild != null) {
                     // FIXME may want to only add certain ABIs
-                    addDerivedPlan(ctsBuild, AbiUtils.getAbisSupportedByCts(), flatArgs);
+                    addDerivedPlan(ctsBuild, AbiUtils.getAbisSupportedByCompatibility(), flatArgs);
                 }
             }
         };
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java b/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
index 61561a5..0ab70a7 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
@@ -15,7 +15,7 @@
  */
 package com.android.cts.tradefed.device;
 
-import com.android.cts.util.AbiUtils;
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.result.CtsXmlResultReporter;
 import com.android.ddmlib.IDevice;
 import com.android.ddmlib.Log;
@@ -48,14 +48,14 @@
     public static final String EXTENDED_APP_PACKAGE_NAME =
             "com.android.compatibility.common.deviceinfo";
     private static final String EXTENDED_INSTRUMENTATION_NAME =
-            "com.android.compatibility.common.deviceinfo.DeviceInfoInstrument";
+            "android.support.test.runner.AndroidJUnitRunner";
     private static final String DEVICE_INFO_FILES = "device-info-files";
 
     public static final Set<String> IDS = new HashSet<String>();
     public static final Set<String> EXTENDED_IDS = new HashSet<String>();
 
     static {
-        for (String abi : AbiUtils.getAbisSupportedByCts()) {
+        for (String abi : AbiUtils.getAbisSupportedByCompatibility()) {
             IDS.add(AbiUtils.createId(abi, APP_PACKAGE_NAME));
             EXTENDED_IDS.add(AbiUtils.createId(abi, EXTENDED_APP_PACKAGE_NAME));
         }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsTestLogReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsTestLogReporter.java
index b7f064f..8500d01 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsTestLogReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsTestLogReporter.java
@@ -16,8 +16,8 @@
 
 package com.android.cts.tradefed.result;
 
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.device.DeviceInfoCollector;
-import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.TestIdentifier;
@@ -35,6 +35,8 @@
  */
 public class CtsTestLogReporter extends StubTestInvocationListener implements IShardableListener {
 
+    private static final String DEVICE_INFO_ERROR = "DEVICE_INFO_ERROR_";
+
     @Option(name = "quiet-output", description = "Mute display of test results.")
     private boolean mQuietOutput = false;
 
@@ -84,6 +86,9 @@
      */
     @Override
     public void testStarted(TestIdentifier test) {
+        if (mIsExtendedDeviceInfoRun) {
+            return;
+        }
         mCurrentPkgResult.insertTest(test);
     }
 
@@ -92,6 +97,9 @@
      */
     @Override
     public void testFailed(TestIdentifier test, String trace) {
+        if (mIsExtendedDeviceInfoRun) {
+            return;
+        }
         mCurrentPkgResult.reportTestFailure(test, CtsTestStatus.FAIL, trace);
     }
 
@@ -100,6 +108,9 @@
      */
     @Override
     public void testAssumptionFailure(TestIdentifier test, String trace) {
+        if (mIsExtendedDeviceInfoRun) {
+            return;
+        }
         // TODO: do something different here?
         mCurrentPkgResult.reportTestFailure(test, CtsTestStatus.FAIL, trace);
     }
@@ -109,6 +120,17 @@
      */
     @Override
     public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
+        if (mIsExtendedDeviceInfoRun) {
+            for (Map.Entry<String, String> metricsEntry : testMetrics.entrySet()) {
+                String key = metricsEntry.getKey();
+                String value = metricsEntry.getValue();
+                if (key.startsWith(DEVICE_INFO_ERROR)) {
+                    throw new RuntimeException(String.format(
+                        "Error collecting extended device info: %s=%s", key, value));
+                }
+            }
+            return;
+        }
         mCurrentPkgResult.reportTestEnded(test, testMetrics);
         Test result = mCurrentPkgResult.findTest(test);
         String stack = result.getStackTrace() == null ? "" : "\n" + result.getStackTrace();
@@ -121,6 +143,9 @@
      */
     @Override
     public void invocationEnded(long elapsedTime) {
+        if (mIsExtendedDeviceInfoRun) {
+            return;
+        }
         // display the results of the last completed run
         if (mCurrentPkgResult != null) {
             logCompleteRun(mCurrentPkgResult);
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
index 3efc7fc..07caaef 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -61,6 +61,8 @@
         implements ITestInvocationListener, ITestSummaryListener, ILogSaverListener {
 
     private static final String LOG_TAG = "CtsXmlResultReporter";
+    private static final String DEVICE_INFO = "DEVICE_INFO_";
+    private static final String DEVICE_INFO_EXT = ".deviceinfo.json";
 
     public static final String CTS_RESULT_DIR = "cts-result-dir";
     static final String TEST_RESULT_FILE_NAME = "testResult.xml";
@@ -238,6 +240,7 @@
     @Override
     public void testLogSaved(String dataName, LogDataType dataType, InputStreamSource dataStream,
             LogFile logFile) {
+        CLog.i("Got log for %s %s %s", dataName, dataType, logFile.getUrl());
         if (mIncludeTestLogTags && mCurrentTest != null) {
             TestLog log = TestLog.fromDataName(dataName, logFile.getUrl());
             if (log != null) {
@@ -335,9 +338,10 @@
 
     private void checkExtendedDeviceInfoMetrics(Map<String, String> runMetrics) {
         for (Map.Entry<String, String> metricEntry : runMetrics.entrySet()) {
+            String key = metricEntry.getKey();
             String value = metricEntry.getValue();
-            if (!value.endsWith(".deviceinfo.json")) {
-                CLog.e(String.format("%s failed: %s", metricEntry.getKey(), value));
+            if (!key.startsWith(DEVICE_INFO) && !value.endsWith(DEVICE_INFO_EXT)) {
+                CLog.e(String.format("%s failed: %s", key, value));
             }
         }
     }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/PlanCreator.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/PlanCreator.java
index 3881c0e..0926635 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/PlanCreator.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/PlanCreator.java
@@ -22,7 +22,6 @@
 import com.android.cts.tradefed.testtype.ITestPlan;
 import com.android.cts.tradefed.testtype.TestPackageRepo;
 import com.android.cts.tradefed.testtype.TestPlan;
-import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.TestIdentifier;
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/Test.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/Test.java
index 12a2b29..e25ea5a 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/Test.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/Test.java
@@ -15,7 +15,8 @@
  */
 package com.android.cts.tradefed.result;
 
-import com.android.ddmlib.Log;
+import com.android.compatibility.common.util.MetricsXmlSerializer;
+import com.android.compatibility.common.util.ReportLog;
 import com.android.cts.tradefed.result.TestLog.TestLogType;
 
 import org.kxml2.io.KXmlSerializer;
@@ -38,27 +39,13 @@
     private static final String RESULT_ATTR = "result";
     private static final String SCENE_TAG = "FailedScene";
     private static final String STACK_TAG = "StackTrace";
-    private static final String SUMMARY_TAG = "Summary";
-    private static final String DETAILS_TAG = "Details";
-    private static final String VALUEARRAY_TAG = "ValueArray";
-    private static final String VALUE_TAG = "Value";
-    private static final String TARGET_ATTR = "target";
-    private static final String SCORETYPE_ATTR = "scoreType";
-    private static final String UNIT_ATTR = "unit";
-    private static final String SOURCE_ATTR = "source";
-    // separators for the message
-    private static final String LOG_SEPARATOR = "\\+\\+\\+";
-    private static final String LOG_ELEM_SEPARATOR = "\\|";
-
     private String mName;
     private CtsTestStatus mResult;
     private String mStartTime;
     private String mEndTime;
     private String mMessage;
     private String mStackTrace;
-    // summary and details passed from cts
-    private String mSummary;
-    private String mDetails;
+    private ReportLog mReport;
 
     /**
      * Log info for this test like a logcat dump or bugreport.
@@ -73,7 +60,7 @@
     }
 
     /**
-     * Create a {@link Test} from a {@link TestResult}.
+     * Create a {@link Test}.
      *
      * @param name
      */
@@ -135,20 +122,12 @@
         mMessage = getFailureMessageFromStackTrace(mStackTrace);
     }
 
-    public String getSummary() {
-        return mSummary;
+    public ReportLog getReportLog() {
+        return mReport;
     }
 
-    public void setSummary(String summary) {
-        mSummary = summary;
-    }
-
-    public String getDetails() {
-        return mDetails;
-    }
-
-    public void setDetails(String details) {
-        mDetails = details;
+    public void setReportLog(ReportLog report) {
+        mReport = report;
     }
 
     public void updateEndTime() {
@@ -185,113 +164,12 @@
             }
             serializer.endTag(CtsXmlResultReporter.ns, SCENE_TAG);
         }
-        if (mSummary != null) {
-            // <Summary message = "screen copies per sec" scoretype="higherBetter" unit="fps">
-            // 23938.82978723404</Summary>
-            PerfResultSummary summary = parseSummary(mSummary);
-            if (summary != null) {
-                serializer.startTag(CtsXmlResultReporter.ns, SUMMARY_TAG);
-                serializer.attribute(CtsXmlResultReporter.ns, MESSAGE_ATTR, summary.mMessage);
-                if (summary.mTarget.length() != 0 && !summary.mTarget.equals(" ")) {
-                    serializer.attribute(CtsXmlResultReporter.ns, TARGET_ATTR, summary.mTarget);
-                }
-                serializer.attribute(CtsXmlResultReporter.ns, SCORETYPE_ATTR, summary.mType);
-                serializer.attribute(CtsXmlResultReporter.ns, UNIT_ATTR, summary.mUnit);
-                serializer.text(summary.mValue);
-                serializer.endTag(CtsXmlResultReporter.ns, SUMMARY_TAG);
-                // add details only if summary is present
-                // <Details>
-                //   <ValueArray source=”com.android.cts.dram.BandwidthTest#doRunMemcpy:98”
-                //                    message=”measure1” unit="ms" scoretype="higherBetter">
-                //     <Value>0.0</Value>
-                //     <Value>0.1</Value>
-                //   </ValueArray>
-                // </Details>
-                if (mDetails != null) {
-                    PerfResultDetail[] ds = parseDetails(mDetails);
-                    serializer.startTag(CtsXmlResultReporter.ns, DETAILS_TAG);
-                        for (PerfResultDetail d : ds) {
-                            if (d == null) {
-                                continue;
-                            }
-                            serializer.startTag(CtsXmlResultReporter.ns, VALUEARRAY_TAG);
-                            serializer.attribute(CtsXmlResultReporter.ns, SOURCE_ATTR, d.mSource);
-                            serializer.attribute(CtsXmlResultReporter.ns, MESSAGE_ATTR,
-                                    d.mMessage);
-                            serializer.attribute(CtsXmlResultReporter.ns, SCORETYPE_ATTR, d.mType);
-                            serializer.attribute(CtsXmlResultReporter.ns, UNIT_ATTR, d.mUnit);
-                            for (String v : d.mValues) {
-                                if (v == null) {
-                                    continue;
-                                }
-                                serializer.startTag(CtsXmlResultReporter.ns, VALUE_TAG);
-                                serializer.text(v);
-                                serializer.endTag(CtsXmlResultReporter.ns, VALUE_TAG);
-                            }
-                            serializer.endTag(CtsXmlResultReporter.ns, VALUEARRAY_TAG);
-                        }
-                    serializer.endTag(CtsXmlResultReporter.ns, DETAILS_TAG);
-                }
-            }
-        }
+        MetricsXmlSerializer metricsXmlSerializer = new MetricsXmlSerializer(serializer);
+        metricsXmlSerializer.serialize(mReport);
         serializer.endTag(CtsXmlResultReporter.ns, TAG);
     }
 
     /**
-     *  class containing performance result.
-     */
-    public static class PerfResultCommon {
-        public String mMessage;
-        public String mType;
-        public String mUnit;
-    }
-
-    private class PerfResultSummary extends PerfResultCommon {
-        public String mTarget;
-        public String mValue;
-    }
-
-    private class PerfResultDetail extends PerfResultCommon {
-        public String mSource;
-        public String[] mValues;
-    }
-
-    private PerfResultSummary parseSummary(String summary) {
-        String[] elems = summary.split(LOG_ELEM_SEPARATOR);
-        PerfResultSummary r = new PerfResultSummary();
-        if (elems.length < 5) {
-            Log.w(TAG, "wrong message " + summary);
-            return null;
-        }
-        r.mMessage = elems[0];
-        r.mTarget = elems[1];
-        r.mType = elems[2];
-        r.mUnit = elems[3];
-        r.mValue = elems[4];
-        return r;
-    }
-
-    private PerfResultDetail[] parseDetails(String details) {
-        String[] arrays = details.split(LOG_SEPARATOR);
-        PerfResultDetail[] rs = new PerfResultDetail[arrays.length];
-        for (int i = 0; i < arrays.length; i++) {
-            String[] elems = arrays[i].split(LOG_ELEM_SEPARATOR);
-            if (elems.length < 5) {
-                Log.w(TAG, "wrong message " + arrays[i]);
-                continue;
-            }
-            PerfResultDetail r = new PerfResultDetail();
-            r.mSource = elems[0];
-            r.mMessage = elems[1];
-            r.mType = elems[2];
-            r.mUnit = elems[3];
-            r.mValues = elems[4].split(" ");
-            rs[i] = r;
-        }
-        return rs;
-    }
-
-    /**
      * Strip out any invalid XML characters that might cause the report to be unviewable.
      * http://www.w3.org/TR/REC-xml/#dt-character
      */
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java
index 45224f6..2229671 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java
@@ -15,9 +15,10 @@
  */
 package com.android.cts.tradefed.result;
 
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.compatibility.common.util.MetricsStore;
+import com.android.compatibility.common.util.ReportLog;
 import com.android.cts.tradefed.testtype.CtsTest;
-import com.android.cts.tradefed.util.CtsHostStore;
-import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.log.LogUtil.CLog;
 
@@ -33,8 +34,6 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 /**
  * Data structure for a CTS test package result.
@@ -45,7 +44,7 @@
 
     static final String TAG = "TestPackage";
 
-    public static final String CTS_RESULT_KEY = "CTS_TEST_RESULT";
+    public static final String RESULT_KEY = "COMPATIBILITY_TEST_RESULT";
 
     private static final String DIGEST_ATTR = "digest";
     private static final String APP_PACKAGE_NAME_ATTR = "appPackageName";
@@ -54,8 +53,6 @@
     private static final String ns = CtsXmlResultReporter.ns;
     private static final String SIGNATURE_TEST_PKG = "android.tests.sigtest";
 
-    private static final Pattern mCtsLogPattern = Pattern.compile("(.*)\\+\\+\\+\\+(.*)");
-
     private String mDeviceSerial;
     private String mAppPackageName;
     private String mName;
@@ -249,23 +246,22 @@
         // Collect performance results
         for (TestIdentifier test : mTestMetrics.keySet()) {
             // device test can have performance results in test metrics
-            String perfResult = mTestMetrics.get(test).get(CTS_RESULT_KEY);
-            // host test should be checked in CtsHostStore.
-            if (perfResult == null) {
-                perfResult = CtsHostStore.removeCtsResult(mDeviceSerial, mAbi, test.toString());
+            String perfResult = mTestMetrics.get(test).get(RESULT_KEY);
+            ReportLog report = null;
+            if (perfResult != null) {
+                try {
+                    report = ReportLog.parse(perfResult);
+                } catch (XmlPullParserException | IOException e) {
+                    e.printStackTrace();
+                }
+            } else {
+                // host test should be checked into MetricsStore.
+                report = MetricsStore.removeResult(mDeviceSerial, getAbi(), test.toString());
             }
             Test result = findTest(test);
-            if (perfResult != null && !result.getResult().equals(CtsTestStatus.FAIL)) {
-                // CTS result is passed in Summary++++Details format.
-                // Extract Summary and Details, and pass them.
-                Matcher m = mCtsLogPattern.matcher(perfResult);
-                if (m.find()) {
-                    result.setResultStatus(CtsTestStatus.PASS);
-                    result.setSummary(m.group(1));
-                    result.setDetails(m.group(2));
-                } else {
-                    CLog.e("CTS Result unrecognizable:" + perfResult);
-                }
+            if (report != null && !result.getResult().equals(CtsTestStatus.FAIL)) {
+                result.setResultStatus(CtsTestStatus.PASS);
+                result.setReportLog(report);
             }
         }
     }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestResults.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestResults.java
index 9f67f2d..a3f1591 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestResults.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestResults.java
@@ -15,8 +15,8 @@
  */
 package com.android.cts.tradefed.result;
 
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.build.CtsBuildProvider;
-import com.android.cts.util.AbiUtils;
 import com.android.tradefed.log.LogUtil.CLog;
 
 import org.kxml2.io.KXmlSerializer;
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsRootDeviceSetup.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsRootDeviceSetup.java
index 0e768e2..f75a99e 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsRootDeviceSetup.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsRootDeviceSetup.java
@@ -41,7 +41,7 @@
  */
 public class CtsRootDeviceSetup implements ITargetPreparer {
 
-    private static final String DEVICE_ADMIN_APK_FILE_NAME = "CtsDeviceAdmin.apk";
+    private static final String DEVICE_ADMIN_APK_FILE_NAME = "CtsAdminApp.apk";
 
     /**
      * {@inheritDoc}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsInstrumentationApkTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsInstrumentationApkTest.java
index 66d1135f..1fa4e7b 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsInstrumentationApkTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsInstrumentationApkTest.java
@@ -15,8 +15,8 @@
  */
 package com.android.cts.tradefed.testtype;
 
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
index 244f348..dc0d040 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
@@ -16,11 +16,11 @@
 
 package com.android.cts.tradefed.testtype;
 
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.build.CtsBuildHelper;
 import com.android.cts.tradefed.device.DeviceInfoCollector;
 import com.android.cts.tradefed.result.CtsTestStatus;
 import com.android.cts.tradefed.result.PlanCreator;
-import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.TestIdentifier;
@@ -64,7 +64,6 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
@@ -252,20 +251,6 @@
         }
     }
 
-
-    /**
-     * A {@link Comparator} for sorting {@link TestPackage}s by running time hint.
-     */
-    static class RuntimeHintComparator implements Comparator<TestPackage> {
-
-        @Override
-        public int compare(TestPackage left, TestPackage right) {
-            return Long.compare(left.getPackageDef().getRuntimeHint(),
-                    right.getPackageDef().getRuntimeHint());
-        }
-
-    }
-
     /**
      * A {@link ResultForwarder} that will forward a bugreport on each failed test.
      */
@@ -826,10 +811,6 @@
             int numTestPackages = testPackageList.size();
             int totalShards = Math.min(mTotalShards, numTestPackages);
 
-            // Sort test packages by running time hint, to force packages with large expected
-            // running times to different shards if possible.
-            Collections.sort(testPackageList, new RuntimeHintComparator());
-
             List<TestPackage> shardTestPackageList = new ArrayList<>();
             for (int i = mShardAssignment; i < numTestPackages; i += totalShards) {
                 shardTestPackageList.add(testPackageList.get(i));
@@ -1096,7 +1077,7 @@
      * Exposed for unit testing
      */
     ITestPlan createPlan(String planName) {
-        return new TestPlan(planName, AbiUtils.getAbisSupportedByCts());
+        return new TestPlan(planName, AbiUtils.getAbisSupportedByCompatibility());
     }
 
     /**
@@ -1110,7 +1091,7 @@
         String bitness = (mForceAbi == null) ? "" : mForceAbi;
         Set<String> abis = new HashSet<>();
         for (String abi : AbiFormatter.getSupportedAbis(mDevice, bitness)) {
-            if (AbiUtils.isAbiSupportedByCts(abi)) {
+            if (AbiUtils.isAbiSupportedByCompatibility(abi)) {
                 abis.add(abi);
             }
         }
@@ -1125,7 +1106,7 @@
      */
     ITestPlan createPlan(PlanCreator planCreator)
             throws ConfigurationException {
-        return planCreator.createDerivedPlan(mCtsBuild, AbiUtils.getAbisSupportedByCts());
+        return planCreator.createDerivedPlan(mCtsBuild, AbiUtils.getAbisSupportedByCompatibility());
     }
 
     /**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
index 6f4d42d..66fcd44 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
@@ -1,7 +1,7 @@
 package com.android.cts.tradefed.testtype;
 
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.AdbCommandRejectedException;
 import com.android.ddmlib.IShellOutputReceiver;
 import com.android.ddmlib.MultiLineReceiver;
@@ -161,7 +161,7 @@
     }
 
     private static final class CapabilityQueryFailureException extends Exception {
-    };
+    }
 
     /**
      * Test configuration of dEPQ test instance execution.
@@ -241,13 +241,13 @@
         private boolean mGotTestResult;
         private String mCurrentTestLog;
 
-        private class PendingResult
-        {
+        private class PendingResult {
             boolean allInstancesPassed;
             Map<BatchRunConfiguration, String> testLogs;
             Map<BatchRunConfiguration, String> errorMessages;
             Set<BatchRunConfiguration> remainingConfigs;
-        };
+        }
+
         private final Map<TestIdentifier, PendingResult> mPendingResults = new HashMap<>();
 
         public void setSink(ITestInvocationListener sink) {
@@ -728,7 +728,7 @@
      */
     public static interface ISleepProvider {
         public void sleep(int milliseconds);
-    };
+    }
 
     private static class SleepProvider implements ISleepProvider {
         public void sleep(int milliseconds) {
@@ -737,7 +737,7 @@
             } catch (InterruptedException ex) {
             }
         }
-    };
+    }
 
     /**
      * Interface for failure recovery.
@@ -997,7 +997,7 @@
         private void rebootDevice() throws DeviceNotAvailableException {
             mDevice.reboot();
         }
-    };
+    }
 
     /**
      * Parse map of instance arguments to map of BatchRunConfigurations
@@ -1319,12 +1319,13 @@
         public AdbComLinkOpenError(String description, Throwable inner) {
             super(description, inner);
         }
-    };
+    }
+
     private static final class AdbComLinkKilledError extends Exception {
         public AdbComLinkKilledError(String description, Throwable inner) {
             super(description, inner);
         }
-    };
+    }
 
     /**
      * Executes a given command in adb shell
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
index 9cbcd20..f11c76d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.tradefed.testtype;
 
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.build.CtsBuildHelper;
 import com.android.ddmlib.testrunner.ITestRunListener;
 import com.android.tradefed.build.IBuildInfo;
@@ -149,7 +150,8 @@
     }
 
     void runTest(ITestRunListener listener) throws DeviceNotAvailableException {
-        GeeTestResultParser resultParser = new GeeTestResultParser(mPackageName, listener);
+        String id = AbiUtils.createId(mAbi.getName(), mPackageName);
+        GeeTestResultParser resultParser = new GeeTestResultParser(id, listener);
         resultParser.setFakePackagePrefix(mPackageName + ".");
 
         String fullPath = NATIVE_TESTS_DIRECTORY + ANDROID_PATH_SEPARATOR + mExeName;
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
index 630dee3..13f3572 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
@@ -72,11 +72,6 @@
     public IAbi getAbi();
 
     /**
-     * @return the estimated running time of this test package.
-     */
-    public long getRuntimeHint();
-
-    /**
      * Set the filter to use for tests
      *
      * @param testFilter
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageRepo.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageRepo.java
index 234f437..893758f 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageRepo.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageRepo.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.tradefed.testtype;
 
-import com.android.cts.util.AbiUtils;
+import com.android.compatibility.common.util.AbiUtils;
 
 import java.util.List;
 import java.util.Map;
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
index d08c0bc..b75a67a 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.tradefed.testtype;
 
-import com.android.cts.util.AbiUtils;
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.log.LogUtil.CLog;
@@ -66,7 +66,6 @@
     private String mRunTimeArgs = null;
     private String mTestPackageName = null;
     private String mDigest = null;
-    private long mRuntimeHint = 0;
     private IAbi mAbi = null;
     private List<ITargetPreparer> mPreparers = null;
 
@@ -138,18 +137,6 @@
      * {@inheritDoc}
      */
     @Override
-    public long getRuntimeHint() {
-        return mRuntimeHint;
-    }
-
-    void setRuntimeHint(long runtimeHint) {
-        mRuntimeHint = runtimeHint;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
     public String getName() {
         return mName;
     }
@@ -254,7 +241,7 @@
                 CLog.d("Setting new timeout to " + mTimeoutInMins + " mins");
                 hostTest.setTimeout(mTimeoutInMins * 60 * 1000);
             }
-            hostTest.setRunName(mAppPackageName);
+            hostTest.setRunName(getId());
             hostTest.setJarFileName(mJarPath);
             hostTest.setTests(mTests);
             hostTest.setAbi(mAbi);
@@ -263,7 +250,7 @@
         } else if (VM_HOST_TEST.equals(mTestType)) {
             CLog.d("Creating vm host test for %s", mName);
             VMHostTest vmHostTest = new VMHostTest();
-            vmHostTest.setRunName(mAppPackageName);
+            vmHostTest.setRunName(getId());
             vmHostTest.setJarFileName(mJarPath);
             vmHostTest.setTests(mTests);
             vmHostTest.setAbi(mAbi);
@@ -285,11 +272,12 @@
             return wrappedGeeTest;
         } else if (UIAUTOMATOR_TEST.equals(mTestType)) {
             UiAutomatorJarTest uiautomatorTest = new UiAutomatorJarTest();
+            uiautomatorTest.setRunName(getId());
             return setUiAutomatorTest(uiautomatorTest);
         } else if (JUNIT_DEVICE_TEST.equals(mTestType)){
             CLog.d("Creating JUnit device test %s", mName);
             JUnitDeviceTest jUnitDeviceTest = new JUnitDeviceTest();
-            jUnitDeviceTest.setRunName(mAppPackageName);
+            jUnitDeviceTest.setRunName(getId());
             jUnitDeviceTest.addTestJarFileName(mJarPath);
             jUnitDeviceTest.addRunTimeArgs(mRunTimeArgs);
             jUnitDeviceTest.setTests(mTests);
@@ -318,7 +306,7 @@
      */
     private InstrumentationTest setInstrumentationTest(CtsInstrumentationApkTest instrTest,
             File testCaseDir) {
-        instrTest.setRunName(mAppPackageName);
+        instrTest.setRunName(getId());
         instrTest.setPackageName(mAppNameSpace);
         instrTest.setRunnerName(mRunner);
         instrTest.setAbi(mAbi);
@@ -353,7 +341,7 @@
         } else {
             uiautomatorTest.addClassNames(mTestClasses);
         }
-        uiautomatorTest.setRunName(mAppPackageName);
+        uiautomatorTest.setRunName(getId());
         uiautomatorTest.setCaptureLogs(false);
         return uiautomatorTest;
     }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
index 7e16170..9857105b 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
@@ -15,7 +15,7 @@
  */
 package com.android.cts.tradefed.testtype;
 
-import com.android.cts.util.AbiUtils;
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.ddmlib.Log;
 import com.android.tradefed.config.ConfigurationException;
 import com.android.tradefed.config.ConfigurationFactory;
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
index 951c461..acd977e 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
@@ -15,7 +15,7 @@
  */
 package com.android.cts.tradefed.testtype;
 
-import com.android.cts.util.AbiUtils;
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.util.xml.AbstractXmlParser;
@@ -86,12 +86,8 @@
                 final String targetNameSpace = attributes.getValue("targetNameSpace");
                 final String runTimeArgs = attributes.getValue("runtimeArgs");
                 final String testType = getTestType(attributes);
-                long runTimeHint = 0;
-                if (attributes.getValue("runtimeHint") != null) {
-                    runTimeHint = Long.parseLong(attributes.getValue("runtimeHint"));
-                }
 
-                for (String abiName : AbiUtils.getAbisSupportedByCts()) {
+                for (String abiName : AbiUtils.getAbisSupportedByCompatibility()) {
                     Abi abi = new Abi(abiName, AbiUtils.getBitness(abiName));
                     TestPackageDef packageDef = new TestPackageDef();
                     packageDef.setAppPackageName(appPackageName);
@@ -106,7 +102,6 @@
                     }
                     packageDef.setTargetBinaryName(targetBinaryName);
                     packageDef.setTargetNameSpace(targetNameSpace);
-                    packageDef.setRuntimeHint(runTimeHint);
                     packageDef.setAbi(abi);
                     mPackageDefs.put(abiName, packageDef);
                 }
@@ -159,7 +154,7 @@
                         Set<String> abis = new HashSet<String>();
                         if (abiList == null) {
                             // If no specification, add all supported abis
-                            abis.addAll(AbiUtils.getAbisSupportedByCts());
+                            abis.addAll(AbiUtils.getAbisSupportedByCompatibility());
                         } else {
                             for (String abi : abiList.split(",")) {
                                 // Else only add the abi which are supported
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPlan.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPlan.java
index 2419784..6b02db9 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPlan.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPlan.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.tradefed.testtype;
 
-import com.android.cts.util.AbiUtils;
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.util.ArrayUtil;
 import com.android.tradefed.util.xml.AbstractXmlParser;
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/WrappedGTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/WrappedGTest.java
index e3ff8257..4f40c89 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/WrappedGTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/WrappedGTest.java
@@ -16,8 +16,8 @@
 
 package com.android.cts.tradefed.testtype;
 
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.testrunner.ITestRunListener;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/util/CtsHostStore.java b/tools/tradefed-host/src/com/android/cts/tradefed/util/CtsHostStore.java
deleted file mode 100644
index 288b48c..0000000
--- a/tools/tradefed-host/src/com/android/cts/tradefed/util/CtsHostStore.java
+++ /dev/null
@@ -1,59 +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.tradefed.util;
-
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Utility class for storing Cts Results.
- * This is necessary for host tests where test metrics cannot be passed.
- */
-public class CtsHostStore {
-
-    // needs concurrent version as there can be multiple client accessing this.
-    // But there is no additional protection for the same key as that should not happen.
-    private static final ConcurrentHashMap<String, String> mMap =
-            new ConcurrentHashMap<String, String>();
-
-    /**
-     * Stores CTS result. Existing result with the same key will be replaced.
-     * Note that key is generated in the form of device_serial#class#method name.
-     * So there should be no concurrent test for the same (serial, class, method).
-     * @param deviceSerial
-     * @param abi
-     * @param classMethodName
-     * @param result CTS result string
-     */
-    public static void storeCtsResult(String deviceSerial, String abi, String classMethodName, String result) {
-        mMap.put(generateTestKey(deviceSerial, abi, classMethodName), result);
-    }
-
-    /**
-     * retrieves a CTS result for the given condition and remove it from the internal
-     * storage. If there is no result for the given condition, it will return null.
-     */
-    public static String removeCtsResult(String deviceSerial, String abi, String classMethodName) {
-        return mMap.remove(generateTestKey(deviceSerial, abi, classMethodName));
-    }
-
-    /**
-     * @return test key in the form of device_serial#abi#class_name#method_name
-     */
-    private static String generateTestKey(String deviceSerial, String abi, String classMethodName) {
-        return String.format("%s#%s#%s", deviceSerial, abi, classMethodName);
-
-    }
-}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/util/HostReportLog.java b/tools/tradefed-host/src/com/android/cts/tradefed/util/HostReportLog.java
index 645dbb9..f72b097 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/util/HostReportLog.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/util/HostReportLog.java
@@ -16,17 +16,17 @@
 
 package com.android.cts.tradefed.util;
 
+import com.android.compatibility.common.util.MetricsReportLog;
 import com.android.cts.util.ReportLog;
 
 /**
  * ReportLog for host tests
  * Note that setTestInfo should be set before throwing report
+ *
+ * This class is deprecated, use {@link MetricsReportLog} instead.
  */
+@Deprecated
 public class HostReportLog extends ReportLog {
-    private final String mDeviceSerial;
-    private final String mAbiName;
-    private final String mClassMethodName;
-
     /**
      * @param deviceSerial serial number of the device
      * @param abiName the name of the ABI on which the test was run
@@ -34,12 +34,10 @@
      *        Note that ReportLog.getClassMethodNames() provide this.
      */
     public HostReportLog(String deviceSerial, String abiName, String classMethodName) {
-        mDeviceSerial = deviceSerial;
-        mAbiName = abiName;
-        mClassMethodName = classMethodName;
+        super(new MetricsReportLog(deviceSerial, abiName, classMethodName));
     }
 
     public void deliverReportToHost() {
-        CtsHostStore.storeCtsResult(mDeviceSerial, mAbiName, mClassMethodName, generateReport());
+        ((MetricsReportLog) mReportLog).submit();
     }
-}
+}
\ No newline at end of file
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
index 958dbe4..361b91c 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
@@ -17,11 +17,10 @@
 
 import static com.android.cts.tradefed.result.CtsXmlResultReporter.CTS_RESULT_FILE_VERSION;
 
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.UnitTests;
-import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.build.IFolderBuildInfo;
-import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.result.LogDataType;
 import com.android.tradefed.result.LogFile;
 import com.android.tradefed.result.TestSummary;
@@ -36,8 +35,8 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java
index 98caad1..19204b7 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java
@@ -15,10 +15,10 @@
  */
 package com.android.cts.tradefed.testtype;
 
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.UnitTests;
 import com.android.cts.tradefed.build.StubCtsBuildHelper;
 import com.android.cts.tradefed.result.PlanCreator;
-import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
index 7ec09c9..2c8a816 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
@@ -15,18 +15,16 @@
  */
 package com.android.cts.tradefed.testtype;
 
-import com.android.cts.tradefed.build.StubCtsBuildHelper;
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.cts.tradefed.UnitTests;
-import com.android.cts.util.AbiUtils;
+import com.android.cts.tradefed.build.StubCtsBuildHelper;
 import com.android.ddmlib.IDevice;
 import com.android.ddmlib.IShellOutputReceiver;
 import com.android.ddmlib.ShellCommandUnresponsiveException;
-import com.android.ddmlib.testrunner.ITestRunListener;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.result.ITestInvocationListener;
-import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.util.IRunUtil;
 import com.android.tradefed.util.RunInterruptedException;
 
@@ -38,7 +36,6 @@
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
index bd48c51..8655885 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.tradefed.testtype;
 
-import com.android.cts.util.AbiUtils;
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
 
@@ -100,7 +100,7 @@
             assertEquals("com.example", def.getAppNameSpace());
             assertEquals("android.example", def.getAppPackageName());
             assertEquals("android.test.InstrumentationTestRunner", def.getRunner());
-            assertTrue(AbiUtils.isAbiSupportedByCts(def.getAbi().getName()));
+            assertTrue(AbiUtils.isAbiSupportedByCompatibility(def.getAbi().getName()));
         }
     }
 
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPlanTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPlanTest.java
index 5b28539..be260ea 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPlanTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPlanTest.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.tradefed.testtype;
 
-import com.android.cts.util.AbiUtils;
+import com.android.compatibility.common.util.AbiUtils;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
 
@@ -75,7 +75,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mPlan = new TestPlan("plan", AbiUtils.getAbisSupportedByCts());
+        mPlan = new TestPlan("plan", AbiUtils.getAbisSupportedByCompatibility());
     }
 
     /**
@@ -91,7 +91,7 @@
      * @param plan
      */
     private void assertTestData(TestPlan plan) {
-        Set<String> abis = AbiUtils.getAbisSupportedByCts();
+        Set<String> abis = AbiUtils.getAbisSupportedByCompatibility();
         assertEquals(2 * abis.size(), plan.getTestIds().size());
         List<String> sortedAbis = new ArrayList<String>(abis);
         Collections.sort(sortedAbis);
@@ -112,7 +112,7 @@
      */
     public void testParse_exclude() throws ParseException  {
         mPlan.parse(getStringAsStream(TEST_EXCLUDED_DATA));
-        Set<String> abis = AbiUtils.getAbisSupportedByCts();
+        Set<String> abis = AbiUtils.getAbisSupportedByCompatibility();
         assertEquals(abis.size(), mPlan.getTestIds().size());
 
         for (String abi : abis) {
@@ -136,7 +136,7 @@
      * @param plan
      */
     private void assertMultiExcluded(TestPlan plan) {
-        Set<String> abis = AbiUtils.getAbisSupportedByCts();
+        Set<String> abis = AbiUtils.getAbisSupportedByCompatibility();
         assertEquals(abis.size(), plan.getTestIds().size());
 
         for (String abi : abis) {
@@ -154,7 +154,7 @@
      */
     public void testParse_classExclude() throws ParseException  {
         mPlan.parse(getStringAsStream(TEST_CLASS_EXCLUDED_DATA));
-        Set<String> abis = AbiUtils.getAbisSupportedByCts();
+        Set<String> abis = AbiUtils.getAbisSupportedByCompatibility();
         assertEquals(abis.size(), mPlan.getTestIds().size());
 
         for (String abi : abis) {
@@ -179,14 +179,14 @@
      * @throws IOException
      */
     public void testSerialize_packages() throws ParseException, IOException  {
-        Set<String> abis = AbiUtils.getAbisSupportedByCts();
+        Set<String> abis = AbiUtils.getAbisSupportedByCompatibility();
         for (String abi : abis) {
             mPlan.addPackage(AbiUtils.createId(abi, TEST_NAME1));
             mPlan.addPackage(AbiUtils.createId(abi, TEST_NAME2));
         }
         ByteArrayOutputStream outStream = new ByteArrayOutputStream();
         mPlan.serialize(outStream);
-        TestPlan parsedPlan = new TestPlan("parsed", AbiUtils.getAbisSupportedByCts());
+        TestPlan parsedPlan = new TestPlan("parsed", AbiUtils.getAbisSupportedByCompatibility());
         parsedPlan.parse(getStringAsStream(outStream.toString()));
         // parsedPlan should contain same contents as TEST_DATA
         assertTestData(parsedPlan);
@@ -196,7 +196,7 @@
      * Test serializing and deserializing plan with multiple excluded tests
      */
     public void testSerialize_multiExclude() throws ParseException, IOException  {
-        Set<String> abis = AbiUtils.getAbisSupportedByCts();
+        Set<String> abis = AbiUtils.getAbisSupportedByCompatibility();
 
         for (String abi : abis) {
             String test1Id = AbiUtils.createId(abi, TEST_NAME1);
@@ -208,7 +208,7 @@
         }
         ByteArrayOutputStream outStream = new ByteArrayOutputStream();
         mPlan.serialize(outStream);
-        TestPlan parsedPlan = new TestPlan("parsed", AbiUtils.getAbisSupportedByCts());
+        TestPlan parsedPlan = new TestPlan("parsed", AbiUtils.getAbisSupportedByCompatibility());
         parsedPlan.parse(getStringAsStream(outStream.toString()));
         // parsedPlan should contain same contents as TEST_DATA
         assertMultiExcluded(parsedPlan);
diff --git a/tools/utils/Android.mk b/tools/utils/Android.mk
index 0ba5cf4..d26abb1 100644
--- a/tools/utils/Android.mk
+++ b/tools/utils/Android.mk
@@ -25,6 +25,6 @@
 LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
 
 LOCAL_JAVA_LIBRARIES := junit
-LOCAL_STATIC_JAVA_LIBRARIES := ctsabiutilslib vogarexpectlib
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-host-util vogarexpectlib
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/utils/CollectAllTests.java b/tools/utils/CollectAllTests.java
index 0bce11c..8003f4d 100644
--- a/tools/utils/CollectAllTests.java
+++ b/tools/utils/CollectAllTests.java
@@ -13,7 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import com.android.cts.util.AbiUtils;
+
+import com.android.compatibility.common.util.AbiUtils;
 
 import org.junit.runner.RunWith;
 import org.w3c.dom.Document;
diff --git a/tools/utils/VogarUtils.java b/tools/utils/VogarUtils.java
index 8e77e7c..77c62da 100644
--- a/tools/utils/VogarUtils.java
+++ b/tools/utils/VogarUtils.java
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-import com.android.cts.util.AbiUtils;
-
 import vogar.Expectation;
 import vogar.ExpectationStore;
 import vogar.ModeId;
 import vogar.Result;
 
+import com.android.compatibility.common.util.AbiUtils;
+
 import java.io.File;
 import java.io.FilenameFilter;
 import java.io.IOException;
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 9f462ca..9ccf468 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -20,6 +20,7 @@
 import os
 import re
 import shutil
+import string
 import subprocess
 import sys
 import xml.dom.minidom as dom
@@ -37,6 +38,16 @@
   f.close()
   return lines
 
+def ReadDeqpTestList(testRoot, file):
+  """Reads a file, converts test names from deqp to CTS format, and returns
+  its contents as a line list.
+  """
+  REPO_ROOT = os.path.join(testRoot, "../../..")
+  f = open(os.path.join(REPO_ROOT, "external/deqp/android/cts", file), 'r');
+  lines = [string.join(line.strip().rsplit('.',1),'#') for line in f.readlines()]
+  f.close()
+  return lines
+
 def GetMakeFileVars(makefile_path):
   """Extracts variable definitions from the given make file.
 
@@ -127,12 +138,12 @@
 
     plan = tools.TestPlan(packages)
     plan.Include(r'android\.core\.tests.*')
-    plan.Exclude(r'android\.core\.tests\.libcore.\package.\harmony*')
+    plan.Exclude(r'android\.core\.tests\.libcore\.package\.harmony*')
     self.__WritePlan(plan, 'Java')
 
     # TODO: remove this once the tests are fixed and merged into Java plan above.
     plan = tools.TestPlan(packages)
-    plan.Include(r'android\.core\.tests\.libcore.\package.\harmony*')
+    plan.Include(r'android\.core\.tests\.libcore\.package\.harmony*')
     self.__WritePlan(plan, 'Harmony')
 
     plan = tools.TestPlan(packages)
@@ -165,7 +176,7 @@
 
     # CTS Stable plan
     plan = tools.TestPlan(packages)
-    plan.Exclude(r'com\.android\.cts\.browserbench')
+    plan.Exclude(r'android\.browser')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     for package, test_list in releasekey_tests.iteritems():
@@ -175,7 +186,7 @@
     # CTS Flaky plan - list of tests known to be flaky in lab environment
     plan = tools.TestPlan(packages)
     plan.Exclude('.*')
-    plan.Include(r'com\.android\.cts\.browserbench')
+    plan.Include(r'android\.browser')
     for package, test_list in flaky_tests.iteritems():
       plan.Include(package+'$')
       plan.IncludeTests(package, test_list)
@@ -190,7 +201,7 @@
     plan.Exclude('.*')
     for package, test_list in small_tests.iteritems():
       plan.Include(package+'$')
-    plan.Exclude(r'com\.android\.cts\.browserbench')
+    plan.Exclude(r'android\.browser')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     for package, test_list in releasekey_tests.iteritems():
@@ -203,7 +214,7 @@
     plan.Exclude('.*')
     for package, test_list in medium_tests.iteritems():
       plan.Include(package+'$')
-    plan.Exclude(r'com\.android\.cts\.browserbench')
+    plan.Exclude(r'android\.browser')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     for package, test_list in releasekey_tests.iteritems():
@@ -215,7 +226,7 @@
     plan = tools.TestPlan(packages)
     plan.Exclude('.*')
     plan.Include(r'android\.hardware$')
-    plan.Exclude(r'com\.android\.cts\.browserbench')
+    plan.Exclude(r'android\.browser')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     for package, test_list in releasekey_tests.iteritems():
@@ -241,7 +252,7 @@
     plan.Exclude('.*')
     plan.Include(r'android\.media$')
     plan.Include(r'android\.view$')
-    plan.Exclude(r'com\.android\.cts\.browserbench')
+    plan.Exclude(r'android\.browser')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     for package, test_list in releasekey_tests.iteritems():
@@ -252,7 +263,7 @@
     plan = tools.TestPlan(packages)
     plan.Exclude('.*')
     plan.Include(r'android\.mediastress$')
-    plan.Exclude(r'com\.android\.cts\.browserbench')
+    plan.Exclude(r'android\.browser')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     for package, test_list in releasekey_tests.iteritems():
@@ -264,7 +275,7 @@
     plan.Exclude('.*')
     for package, test_list in new_test_packages.iteritems():
       plan.Include(package+'$')
-    plan.Exclude(r'com\.android\.cts\.browserbench')
+    plan.Exclude(r'android\.browser')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     for package, test_list in releasekey_tests.iteritems():
@@ -275,8 +286,21 @@
     plan = tools.TestPlan(packages)
     plan.Exclude('.*')
     plan.Include(r'com\.drawelements\.')
+    plan.IncludeTests('com.drawelements.deqp.egl', ReadDeqpTestList(self.test_root, 'mnc/egl-master.txt'))
+    plan.IncludeTests('com.drawelements.deqp.gles2', ReadDeqpTestList(self.test_root, 'mnc/gles2-master.txt'))
+    plan.IncludeTests('com.drawelements.deqp.gles3', ReadDeqpTestList(self.test_root, 'mnc/gles3-master.txt'))
+    plan.IncludeTests('com.drawelements.deqp.gles31', ReadDeqpTestList(self.test_root, 'mnc/gles31-master.txt'))
     self.__WritePlan(plan, 'CTS-DEQP')
 
+    plan = tools.TestPlan(packages)
+    plan.Exclude('.*')
+    plan.Include(r'com\.drawelements\.')
+    plan.ExcludeTests('com.drawelements.deqp.egl', ReadDeqpTestList(self.test_root, 'mnc/egl-master.txt'))
+    plan.ExcludeTests('com.drawelements.deqp.gles2', ReadDeqpTestList(self.test_root, 'mnc/gles2-master.txt'))
+    plan.ExcludeTests('com.drawelements.deqp.gles3', ReadDeqpTestList(self.test_root, 'mnc/gles3-master.txt'))
+    plan.ExcludeTests('com.drawelements.deqp.gles31', ReadDeqpTestList(self.test_root, 'mnc/gles31-master.txt'))
+    self.__WritePlan(plan, 'CTS-DEQP-for-next-rel')
+
     # CTS - sub plan for new test packages added for staging
     plan = tools.TestPlan(packages)
     for package, test_list in small_tests.iteritems():
@@ -290,7 +314,7 @@
     plan.Exclude(r'android\.media$')
     plan.Exclude(r'android\.view$')
     plan.Exclude(r'android\.mediastress$')
-    plan.Exclude(r'com\.android\.cts\.browserbench')
+    plan.Exclude(r'android\.browser')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     for package, test_list in releasekey_tests.iteritems():
@@ -334,7 +358,7 @@
       'android.telephony' : [],
       'android.webkit' : [],
       'android.widget' : [],
-      'com.android.cts.browserbench' : []}
+      'android.browser' : []}
 
 def BuildAospSmallSizeTestList():
   """ Construct a default dict that lists packages names of small tests
@@ -347,6 +371,7 @@
       'android.accounts' : [],
       'android.admin' : [],
       'android.animation' : [],
+      'android.appsecurity' : [],
       'android.bionic' : [],
       'android.bluetooth' : [],
       'android.calendarcommon' : [],
@@ -357,9 +382,11 @@
       'android.core.tests.libcore.package.sun' : [],
       'android.core.tests.libcore.package.tests' : [],
       'android.database' : [],
+      'android.dram' : [],
       'android.dreams' : [],
       'android.drm' : [],
       'android.effect' : [],
+      'android.filesystem' : [],
       'android.gesture' : [],
       'android.graphics' : [],
       'android.graphics2' : [],
@@ -368,7 +395,6 @@
       'android.location' : [],
       'android.nativemedia.sl' : [],
       'android.nativemedia.xa' : [],
-      'android.nativeopengl' : [],
       'android.ndef' : [],
       'android.opengl' : [],
       'android.openglperf' : [],
@@ -381,22 +407,19 @@
       'android.rsg' : [],
       'android.sax' : [],
       'android.signature' : [],
+      'android.simplecpu' : [],
       'android.speech' : [],
-      'android.tests.appsecurity' : [],
       'android.text' : [],
       'android.textureview' : [],
       'android.theme' : [],
       'android.usb' : [],
       'android.util' : [],
-      'com.android.cts.dram' : [],
-      'com.android.cts.filesystemperf' : [],
+      'android.video' : [],
       'com.android.cts.jank' : [],
       'com.android.cts.jank2' : [],
       'com.android.cts.opengl' : [],
-      'com.android.cts.simplecpu' : [],
       'com.android.cts.ui' : [],
       'com.android.cts.uihost' : [],
-      'com.android.cts.videoperf' : [],
       'zzz.android.monkey' : []}
 
 def BuildCtsVettedNewPackagesList():
@@ -516,8 +539,8 @@
       'android.voicesettings' : [
           'android.voicesettings.cts.ZenModeTest#testAll',
       ],
-      'com.android.cts.systemui' : [
-          'com.android.cts.systemui.LightStatusBarTests#testLightStatusBarIcons',
+      'android.systemui.cts' : [
+          'android.systemui.cts.LightStatusBarTests#testLightStatusBarIcons',
       ],
       'com.android.cts.app.os' : [
           'com.android.cts.app.os.OsHostTests#testNonExportedActivities',
diff --git a/tools/utils/java-cert-list-generator.sh b/tools/utils/java-cert-list-generator.sh
index b8cee18..33e9aaa 100755
--- a/tools/utils/java-cert-list-generator.sh
+++ b/tools/utils/java-cert-list-generator.sh
@@ -50,7 +50,7 @@
   static final String[] CERTIFICATE_DATA = {
 STARTCLASS
 
-CERT_DIRECTORY=$ANDROID_BUILD_TOP/libcore/luni/src/main/files/cacerts
+CERT_DIRECTORY=$ANDROID_BUILD_TOP/system/ca-certificates/files/
 for FILE in `ls $CERT_DIRECTORY`; do
   FINGERPRINT=`cat $CERT_DIRECTORY/$FILE | grep "SHA1 Fingerprint=" | cut -d '=' -f 2`
   echo "      \"${FINGERPRINT}\","