Merge "CTS test for the new TelephonyManager APIs" into klp-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 8695981..354775d 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -89,6 +89,9 @@
             <meta-data android:name="test_category" android:value="@string/test_category_device_admin" />
         </activity>
 
+        <!-- A generic activity for intent based tests -->
+        <activity android:name=".IntentDrivenTestActivity"/>
+
         <activity android:name=".admin.ScreenLockTestActivity"
                 android:label="@string/da_screen_lock_test"
                 android:configChanges="keyboardHidden|orientation|screenSize">
@@ -472,9 +475,6 @@
             <meta-data android:name="test_category" android:value="@string/test_category_deskclock" />
         </activity>
 
-        <activity android:name=".deskclock.ShowAlarmsTestActivity"
-                  android:label="@string/dc_show_alarms_test"/>
-
         <receiver android:name=".widget.WidgetCtsProvider">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
diff --git a/apps/CtsVerifier/res/layout/dc_show_alarms.xml b/apps/CtsVerifier/res/layout/dc_show_alarms.xml
deleted file mode 100644
index 06a2bb1..0000000
--- a/apps/CtsVerifier/res/layout/dc_show_alarms.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-    >
-
-    <LinearLayout android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_alignParentTop="true"
-                  android:padding="5dp"
-        >
-
-        <TextView android:layout_width="wrap_content"
-                  android:textSize="18sp"
-                  android:layout_height="wrap_content"
-                  android:text="@string/dc_show_alarms_test_info"
-            />
-
-        <Button android:id="@+id/dc_show_alarms"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/dc_show_alarms_button"
-            />
-    </LinearLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        >
-        <include layout="@layout/pass_fail_buttons" />
-    </LinearLayout>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/intent_driven_test.xml b/apps/CtsVerifier/res/layout/intent_driven_test.xml
new file mode 100644
index 0000000..1b68074
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/intent_driven_test.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+    >
+
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_alignParentTop="true"
+                  android:padding="5dp"
+        >
+
+        <TextView android:id="@+id/info"
+                  android:layout_width="wrap_content"
+                  android:textSize="18sp"
+                  android:layout_height="wrap_content"
+                  android:text="@string/dc_show_alarms_test_info"
+            />
+
+        <LinearLayout android:id="@+id/buttons"
+                      android:orientation="horizontal"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:layout_alignParentTop="true"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        >
+        <include layout="@layout/pass_fail_buttons"/>
+    </LinearLayout>
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index ef14be3..0f164ef 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -15,7 +15,7 @@
 -->
 <resources>
     <string name="app_name">CTS Verifier</string>
-    
+
     <string name="title_version">CTS Verifier %1$s</string>
 
     <string name="pass_button_text">Pass</string>
@@ -32,7 +32,7 @@
     <string name="test_category_security">Security</string>
     <string name="test_category_streaming">Streaming</string>
     <string name="test_category_features">Features</string>
-    <string name="test_category_deskclock">Desk Clock</string>
+    <string name="test_category_deskclock">Clock</string>
     <string name="test_category_other">Other</string>
     <string name="clear">Clear</string>
     <string name="test_results_cleared">Test results cleared.</string>
@@ -617,9 +617,9 @@
     <string name="widget_fail">Fail</string>
 
     <!-- Strings for DeskClock -->
-    <string name="deskclock_tests">Desk Clock Tests</string>
+    <string name="deskclock_tests">Alarms and Timers Tests</string>
     <string name="deskclock_tests_info">
-        The Desk Clock tests verify that the Desk Clock app implements the Clock API\'s properly.
+        The Alarms and Timers tests verify that the Clock app implements the AlarmClock API properly.
     </string>
     <string name="deskclock_group_alarms">Alarms</string>
     <string name="deskclock_group_timers">Timers</string>
@@ -628,9 +628,69 @@
     <string name="dc_show_alarms_test_info">
         This test verifies that the SHOW_ALARMS API works.\n
         1. Press the "Show Alarms" button.\n
-        2. Verify that the Desk Clock app is launched and displays the Alarms section\n
+        2. Verify that a UI of the clock app is launched and displays the list of alarms\n
     </string>
     <string name="dc_show_alarms_button">Show Alarms</string>
 
+    <string name="dc_set_alarm_with_ui_test">Set Alarm Test</string>
+    <string name="dc_set_alarm_with_ui_test_info">
+        This test verifies that the ACTION_SET_ALARM with no parameters API works.\n
+        1. Press the "Set Alarm" button.\n
+        2. Verify that the clock app is launched and displays a UI to manage alarms.\n
+    </string>
+    <string name="dc_set_alarm_button">Set Alarm</string>
+    <string name="dc_set_alarm_verify_button">Verify</string>
 
+    <string name="dc_start_alarm_test">Start Alarm Test</string>
+    <string name="dc_start_alarm_test_info">
+        This test verifies that the ACTION_SET_ALARM API actually starts an alarm.\n
+        1. Press the "Start Alarm" button.\n
+        2. Make sure the alarms UI is NOT shown\n
+        3. Wait for the alarm to fire (may take up to 2 minutes)\n
+        4. Verify that the alarm title is: "Start Alarm Test",\n
+           the alarm is silent and vibrating (if the device supports vibrate).\n
+        5. Dismiss the alarm.\n
+        6. Verify that the alarm is not in the Clock\'s alarms list. The Verify button opens
+           the alarm view.\n
+    </string>
+    <string name="dc_start_alarm_button">Start Alarm</string>
+
+    <string name="dc_full_alarm_test">Full Alarm Test</string>
+    <string name="dc_full_alarm_test_info">
+        This test verifies that the ACTION_SET_ALARM API supports all extras.\n
+        1. Press the "Create Alarm" button.\n
+        2. Verify that you see one alarm with the following information:\n
+           Name of alarm: Create Alarm Test. \n
+           Vibrate: on.\n
+           Ringtone: silent.\n
+           Time:  01:23. \n
+           Repeating on: Monday and Wednesday. \n
+    </string>
+    <string name="dc_full_alarm_button">Create Alarm</string>
+    
+    <string name="dc_set_timer_with_ui_test">Set Timer Test</string>
+    <string name="dc_set_timer_with_ui_test_info">
+        This test verifies that the ACTION_SET_TIMER API with no paramters open the UI\n
+        1. Press the "Set Timer" button.\n
+        2. Verify that the an app is launched and displays a UI to manage timers.\n
+    </string>
+    <string name="dc_set_timer_with_ui_button">Set Timer</string>
+
+    <string name="dc_start_timer_test">Start Timer Test</string>
+    <string name="dc_start_timer_test_info">
+        This test verifies that the ACTION_SET_TIMER API actually starts a timer\n
+        1. Press the "Start Timer" button.\n
+        2. Verify that a timer is started  and NO timers UI is shown.\n
+        3. Verify that the timer named "Start Timer Test" rings after 30 seconds. Dismiss it.\n
+        4. Verify that the timer is deleted after the dismissal.\n
+    </string>
+    <string name="dc_start_timer_button">Start Timer</string>
+
+    <string name="dc_start_timer_with_ui_test">Start Timer With UI Test</string>
+    <string name="dc_start_timer_with_ui_test_info">
+        This test verifies that the ACTION_SET_TIMER API actually starts a timer with UI\n
+        1. Press the "Start Timer" button.\n
+        2. Verify that a timer is started  and the timers UI is shown with a timer named "Start Timer Test".\n
+        3. Verify that the timer rings after 30 seconds.\n
+    </string>
 </resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/IntentDrivenTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/IntentDrivenTestActivity.java
new file mode 100644
index 0000000..9833abd
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/IntentDrivenTestActivity.java
@@ -0,0 +1,215 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+
+package com.android.cts.verifier;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ *  A generic activity for intent based tests.
+ *
+ *  This activity can be reused for various tests that are intent based. The activity consists of a
+ *  text view containing instructions and one or more buttons that trigger intents.
+ *  Each button can send one or more intenrs as startActivity() calls.
+ *
+ *  The intents can either be generated statically and passed as an extra to the intent that started
+ *  this activity or in some cases where the intent needs to be based on dynamic data (for example
+ *  time of day), an {@link IntentFactory} class name can be passed instead. This intent factory
+ *  will dynamically create the intent when the button is clicked based on the test id and the
+ *  button that was clicked.
+ */
+public class IntentDrivenTestActivity extends PassFailButtons.Activity implements OnClickListener {
+    public static final String EXTRA_ID = "id";
+    public static final String EXTRA_TITLE = "title";
+    public static final String EXTRA_INFO = "info";
+    public static final String EXTRA_BUTTONS = "buttons";
+
+    private String mTestId;
+    private ButtonInfo[] mButtonInfos;
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.intent_driven_test);
+        setPassFailButtonClickListeners();
+
+        final Intent intent = getIntent();
+        if (!intent.hasExtra(EXTRA_ID)
+                || !intent.hasExtra(EXTRA_TITLE)
+                || !intent.hasExtra(EXTRA_INFO)
+                || !intent.hasExtra(EXTRA_BUTTONS)) {
+            throw new IllegalArgumentException(
+                    "Intent must have EXTRA_ID, EXTRA_TITLE, EXTRA_INFO & EXTRA_BUTTONS");
+        }
+
+        mTestId = intent.getStringExtra(EXTRA_ID);
+        setTitle(intent.getIntExtra(EXTRA_TITLE, -1));
+
+        final TextView info = (TextView) findViewById(R.id.info);
+        info.setText(intent.getIntExtra(EXTRA_INFO, -1));
+
+        final ViewGroup buttons = (ViewGroup) findViewById(R.id.buttons);
+        final Parcelable[] parcelables = intent.getParcelableArrayExtra(EXTRA_BUTTONS);
+        mButtonInfos = new ButtonInfo[parcelables.length];
+        for (int i = 0; i < parcelables.length; i++) {
+            final ButtonInfo buttonInfo = (ButtonInfo) parcelables[i];
+            mButtonInfos[i] = buttonInfo;
+            final Button button = new Button(this);
+            buttons.addView(button);
+            button.setText(buttonInfo.mButtonText);
+            button.setTag(i);
+            button.setOnClickListener(this);
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        setResult(RESULT_CANCELED);
+    }
+
+    @Override
+    public void onClick(View v) {
+        final ButtonInfo buttonInfo = mButtonInfos[(Integer) v.getTag()];
+        final Intent[] intents = buttonInfo.getIntents();
+        if (intents != null) {
+            for (Parcelable intent : intents) {
+                startActivity((Intent) intent);
+            }
+        } else {
+            final Class<?> factoryClass;
+            final String className = buttonInfo.getIntentFactoryClassName();
+            try {
+                factoryClass = Thread.currentThread().getContextClassLoader().loadClass(className);
+            } catch (ClassNotFoundException e) {
+                throw new IllegalArgumentException("Factory not found: " + className, e);
+            }
+            final IntentFactory factory;
+            try {
+                factory = (IntentFactory) factoryClass.newInstance();
+            } catch (InstantiationException e) {
+                throw new IllegalArgumentException("Can't create factory: " + className, e);
+            } catch (IllegalAccessException e) {
+                throw new IllegalArgumentException("Can't create factory: " + className, e);
+            }
+
+            for (Intent intent : factory.createIntents(mTestId, buttonInfo.getButtonText())) {
+                startActivity(intent);
+            }
+        }
+    }
+
+    @Override
+    public String getTestId() {
+        return mTestId;
+    }
+
+    public static class TestInfo {
+        private final String mTestId;
+        private final int mTitle;
+        private final int mInfoText;
+        private final ButtonInfo[] mButtons;
+
+        public TestInfo(String testId,  int title, int infoText, ButtonInfo... buttons) {
+            mTestId = testId;
+            mTitle = title;
+            mInfoText = infoText;
+            mButtons = buttons;
+        }
+
+        public String getTestId() {
+            return mTestId;
+        }
+
+        public int getTitle() {
+            return mTitle;
+        }
+
+        public int getInfoText() {
+            return mInfoText;
+        }
+
+        public ButtonInfo[] getButtons() {
+            return mButtons;
+        }
+    }
+
+    public static class ButtonInfo implements Parcelable {
+        private final int mButtonText;
+        private final Intent[] mIntents;
+        private final String mIntentFactoryClassName;
+
+        public ButtonInfo(int buttonText, Intent... intents) {
+            mButtonText = buttonText;
+            mIntents = intents;
+            mIntentFactoryClassName = null;
+        }
+
+        public ButtonInfo(int buttonText, String intentFactoryClassName) {
+            mButtonText = buttonText;
+            mIntents = null;
+            mIntentFactoryClassName = intentFactoryClassName;
+        }
+
+        public ButtonInfo(Parcel source) {
+            mButtonText = source.readInt();
+            final Parcelable[] parcelables = source.readParcelableArray(null);
+            if (parcelables != null) {
+                mIntents = new Intent[parcelables.length];
+                for (int i = 0, parcelablesLength = parcelables.length; i < parcelablesLength; i++) {
+                    mIntents[i] = (Intent) parcelables[i];
+                }
+            } else {
+                mIntents = null;
+            }
+            mIntentFactoryClassName = source.readString();
+        }
+
+        public int getButtonText() {
+            return mButtonText;
+        }
+
+        public Intent[] getIntents() {
+            return mIntents;
+        }
+
+        public String getIntentFactoryClassName() {
+            return mIntentFactoryClassName;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mButtonText);
+            dest.writeParcelableArray(mIntents, 0);
+            dest.writeString(mIntentFactoryClassName);
+        }
+
+        public static final Creator<ButtonInfo> CREATOR = new Creator<ButtonInfo>() {
+            public ButtonInfo createFromParcel(Parcel source) {
+                return new ButtonInfo(source);
+            }
+
+            public ButtonInfo[] newArray(int size) {
+                return new ButtonInfo[size];
+            }
+        };
+
+    }
+
+    public interface IntentFactory {
+        Intent[] createIntents(String testId, int buttonText);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java
index 91b9b98..fcd88d1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java
@@ -5,17 +5,125 @@
 import android.content.Intent;
 import android.database.DataSetObserver;
 import android.os.Bundle;
+import android.provider.AlarmClock;
 
 import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.IntentDrivenTestActivity;
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
+import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
+import com.android.cts.verifier.IntentDrivenTestActivity.IntentFactory;
+import com.android.cts.verifier.IntentDrivenTestActivity.TestInfo;
+
+import java.util.ArrayList;
+import java.util.Calendar;
 
 /**
  * Activity that lists all the DeskClock tests.
  */
 public class DeskClockTestsActivity extends PassFailButtons.TestListActivity {
 
+    private static final String SHOW_ALARMS_TEST = "SHOW_ALARMS";
+    public static final String SET_ALARM_WITH_UI_TEST = "SET_ALARM_WITH_UI";
+    public static final String START_ALARM_TEST = "START_ALARM";
+    public static final String CREATE_ALARM_TEST = "CREATE_ALARM";
+    public static final String SET_TIMER_WITH_UI_TEST = "SET_TIMER_WITH_UI";
+    public static final String START_TIMER = "START_TIMER";
+    public static final String START_TIMER_WITH_UI = "START_TIMER_WITH_UI";
+
+    private static final ArrayList<Integer> DAYS = new ArrayList<Integer>();
+
+    private static final Intent CREATE_ALARM_INTENT = new Intent(AlarmClock.ACTION_SET_ALARM)
+            .putExtra(AlarmClock.EXTRA_MESSAGE, "Create Alarm Test")
+            .putExtra(AlarmClock.EXTRA_SKIP_UI, false)
+            .putExtra(AlarmClock.EXTRA_VIBRATE, true)
+            .putExtra(AlarmClock.EXTRA_RINGTONE, AlarmClock.VALUE_RINGTONE_SILENT)
+            .putExtra(AlarmClock.EXTRA_HOUR, 1)
+            .putExtra(AlarmClock.EXTRA_MINUTES, 23)
+            .putExtra(AlarmClock.EXTRA_DAYS, DAYS);
+
+    static {
+        DAYS.add(Calendar.MONDAY);
+        DAYS.add(Calendar.WEDNESDAY);
+    }
+
+    private static final Intent SHOW__ALARMS_INTENT = new Intent(AlarmClock.ACTION_SHOW_ALARMS);
+
+    private static final Intent SET_ALARM_WITH_UI_INTENT = new Intent(AlarmClock.ACTION_SET_ALARM)
+            .putExtra(AlarmClock.EXTRA_SKIP_UI, false);
+
+    private static final Intent SET_TIMER_WITH_UI_INTENT = new Intent(AlarmClock.ACTION_SET_TIMER)
+             .putExtra(AlarmClock.EXTRA_SKIP_UI, false);
+
+    private static final Intent START_TIMER_INTENT = new Intent(AlarmClock.ACTION_SET_TIMER)
+    .putExtra(AlarmClock.EXTRA_SKIP_UI, true)
+    .putExtra(AlarmClock.EXTRA_MESSAGE, "Start Timer Test")
+    .putExtra(AlarmClock.EXTRA_LENGTH, 30);
+
+    private static final Intent START_TIMER_WITH_UI_INTENT = new Intent(AlarmClock.ACTION_SET_TIMER)
+    .putExtra(AlarmClock.EXTRA_SKIP_UI, false)
+    .putExtra(AlarmClock.EXTRA_MESSAGE, "Start Timer Test")
+    .putExtra(AlarmClock.EXTRA_LENGTH, 30);
+
+    private static final TestInfo[] ALARM_TESTS = new TestInfo[] {
+            new TestInfo(
+                    SHOW_ALARMS_TEST,
+                    R.string.dc_show_alarms_test,
+                    R.string.dc_show_alarms_test_info,
+                    new ButtonInfo(
+                            R.string.dc_show_alarms_button,
+                            SHOW__ALARMS_INTENT)),
+            new TestInfo(
+                    SET_ALARM_WITH_UI_TEST,
+                    R.string.dc_set_alarm_with_ui_test,
+                    R.string.dc_set_alarm_with_ui_test_info,
+                    new ButtonInfo(
+                            R.string.dc_set_alarm_button,
+                            SET_ALARM_WITH_UI_INTENT)),
+            new TestInfo(
+                    START_ALARM_TEST,
+                    R.string.dc_start_alarm_test,
+                    R.string.dc_start_alarm_test_info,
+                    new ButtonInfo(
+                            R.string.dc_set_alarm_button,
+                            DeskClockIntentFactory.class.getName()),
+                    new ButtonInfo(
+                            R.string.dc_set_alarm_verify_button,
+                            SHOW__ALARMS_INTENT)),
+            new TestInfo(
+                    CREATE_ALARM_TEST,
+                    R.string.dc_full_alarm_test,
+                    R.string.dc_full_alarm_test_info,
+                    new ButtonInfo(
+                            R.string.dc_full_alarm_button,
+                            CREATE_ALARM_INTENT)),
+    };
+
+    private static final TestInfo[] TIMER_TESTS = new TestInfo[] {
+            new TestInfo(
+                    SET_TIMER_WITH_UI_TEST,
+                    R.string.dc_set_timer_with_ui_test,
+                    R.string.dc_set_timer_with_ui_test_info,
+                    new ButtonInfo(
+                            R.string.dc_set_timer_with_ui_button,
+                            SET_TIMER_WITH_UI_INTENT)),
+            new TestInfo(
+                    START_TIMER,
+                    R.string.dc_start_timer_test,
+                    R.string.dc_start_timer_test_info,
+                    new ButtonInfo(
+                            R.string.dc_start_timer_button,
+                            START_TIMER_INTENT)),
+            new TestInfo(
+                    START_TIMER_WITH_UI,
+                    R.string.dc_start_timer_with_ui_test,
+                    R.string.dc_start_timer_with_ui_test_info,
+                    new ButtonInfo(
+                            R.string.dc_start_timer_button,
+                            START_TIMER_WITH_UI_INTENT)),
+  };
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -28,10 +136,10 @@
         final ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
 
         adapter.add(TestListItem.newCategory(this, R.string.deskclock_group_alarms));
-        adapter.add(TestListItem.newTest(this,
-                R.string.dc_show_alarms_test,
-                ShowAlarmsTestActivity.class.getName(),
-                new Intent(this, ShowAlarmsTestActivity.class), null));
+        addTests(adapter, ALARM_TESTS);
+
+        adapter.add(TestListItem.newCategory(this, R.string.deskclock_group_timers));
+        addTests(adapter, TIMER_TESTS);
 
         adapter.registerDataSetObserver(new DataSetObserver() {
             @Override
@@ -43,10 +151,46 @@
         setTestListAdapter(adapter);
     }
 
+    private void addTests(ArrayTestListAdapter adapter, TestInfo[] tests) {
+        for (TestInfo info : tests) {
+
+            final int title = info.getTitle();
+            adapter.add(TestListItem.newTest(this, title, info.getTestId(),
+            new Intent(this, IntentDrivenTestActivity.class)
+                    .putExtra(IntentDrivenTestActivity.EXTRA_ID, info.getTestId())
+                    .putExtra(IntentDrivenTestActivity.EXTRA_TITLE, title)
+                    .putExtra(IntentDrivenTestActivity.EXTRA_INFO, info.getInfoText())
+                    .putExtra(IntentDrivenTestActivity.EXTRA_BUTTONS, info.getButtons()),
+                    null));
+        }
+    }
+
     /**
      * Enable Pass Button when the all tests passed.
      */
     private void updatePassButton() {
         getPassButton().setEnabled(mAdapter.allTestsPassed());
     }
+
+    public static class DeskClockIntentFactory implements IntentFactory {
+        @Override
+        public Intent[] createIntents(String testId, int buttonText) {
+            if (testId.equals(START_ALARM_TEST)) {
+                // Alarm should go off 2 minutes from now
+                final Calendar cal = Calendar.getInstance();
+                cal.setTimeInMillis(cal.getTimeInMillis() + 120000);
+                return new Intent[] {
+                        new Intent(AlarmClock.ACTION_SET_ALARM)
+                                .putExtra(AlarmClock.EXTRA_MESSAGE, "Start Alarm Test")
+                        .putExtra(AlarmClock.EXTRA_SKIP_UI, true)
+                        .putExtra(AlarmClock.EXTRA_VIBRATE, true)
+                        .putExtra(AlarmClock.EXTRA_RINGTONE, AlarmClock.VALUE_RINGTONE_SILENT)
+                        .putExtra(AlarmClock.EXTRA_HOUR, cal.get(Calendar.HOUR_OF_DAY))
+                        .putExtra(AlarmClock.EXTRA_MINUTES, cal.get(Calendar.MINUTE)),
+                };
+            } else {
+                throw new IllegalArgumentException("Unknown test: " + testId);
+            }
+        }
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/ShowAlarmsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/ShowAlarmsTestActivity.java
deleted file mode 100644
index 0ce8f51..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/ShowAlarmsTestActivity.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2013 Google Inc. All Rights Reserved.
-
-package com.android.cts.verifier.deskclock;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.provider.AlarmClock;
-import android.view.View;
-import android.view.View.OnClickListener;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-public class ShowAlarmsTestActivity extends PassFailButtons.Activity implements OnClickListener {
-
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.dc_show_alarms);
-        setPassFailButtonClickListeners();
-
-        final View button = findViewById(R.id.dc_show_alarms);
-        button.setOnClickListener(this);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        setResult(RESULT_CANCELED);
-    }
-
-    @Override
-    public void onClick(View v) {
-        startActivity(new Intent(AlarmClock.ACTION_SHOW_ALARMS));
-    }
-}
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 6851d94..ec588a4 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -684,6 +684,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.webkit.cts.WebViewStartupStubActivity"
+            android:label="WebViewStartupStubActivity"
+            android:screenOrientation="nosensor">
+            <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.ChildActivity"
                         android:label="ChildActivity" />
 
diff --git a/tests/src/android/webkit/cts/WebViewStartupStubActivity.java b/tests/src/android/webkit/cts/WebViewStartupStubActivity.java
new file mode 100644
index 0000000..6d56efd
--- /dev/null
+++ b/tests/src/android/webkit/cts/WebViewStartupStubActivity.java
@@ -0,0 +1,53 @@
+/*
+ * 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.webkit.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.webkit.WebView;
+
+public class WebViewStartupStubActivity extends Activity {
+    private WebView mWebView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    public WebView createAndAttachWebView() {
+        mWebView = new WebView(this);
+        setContentView(mWebView);
+        return mWebView;
+    }
+
+    public WebView getWebView() {
+        return mWebView;
+    }
+
+    public void detachAndDestroyWebView() {
+        setContentView(null);
+        if (mWebView != null) {
+            mWebView.destroy();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        detachAndDestroyWebView();
+        super.onDestroy();
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorAccelerometerTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorAccelerometerTest.java
new file mode 100644
index 0000000..51fd5f6
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorAccelerometerTest.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.hardware.cts;
+
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+
+public class SensorAccelerometerTest extends SensorCommonTests {
+    @Override
+    protected int getMaxFrequencySupportedInuS() {
+        return 10000; // 100Hz
+    }
+
+    @Override
+    protected int getSensorType() {
+        return Sensor.TYPE_ACCELEROMETER;
+    }
+
+    /**
+     * Regress:
+     * - b/9503957
+     * - b/9611609
+     */
+    @Override
+    public void testEventValidity() {
+        final float THRESHOLD = 0.25f; // m / s^2
+        validateSensorEvent(
+                0 /*x-axis*/,
+                0 /*y-axis*/,
+                SensorManager.STANDARD_GRAVITY /*z-axis*/,
+                THRESHOLD);
+    }
+
+    @Override
+    public void testVarianceWhileStatic() {
+        final float THRESHOLD = 0.25f; // m / s^2
+        validateVarianceWhileStatic(
+                0 /*x-axis*/,
+                0 /*y-axis*/,
+                SensorManager.STANDARD_GRAVITY /*z-axis*/,
+                THRESHOLD);
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorCommonTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorCommonTests.java
new file mode 100644
index 0000000..5cc65bb
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorCommonTests.java
@@ -0,0 +1,695 @@
+/*
+ * 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.hardware.cts;
+
+import android.content.Context;
+
+import android.hardware.FlushCompleteListener;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.TriggerEvent;
+import android.hardware.TriggerEventListener;
+
+import android.os.PowerManager;
+
+import android.test.AndroidTestCase;
+
+import java.util.List;
+import android.util.Log;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import java.text.SimpleDateFormat;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Random;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Class is not marked public to avoid TestRunner to pick the tests in it
+ */
+abstract class SensorCommonTests extends AndroidTestCase {
+    protected final String LOG_TAG = "TestRunner";
+
+    protected SensorManager mSensorManager;
+    protected Sensor mSensorUnderTest;
+    protected TestSensorListener mEventListener;
+
+    private FlushCompleteListener mFlushListener;
+    private PowerManager.WakeLock mWakeLock;
+
+    protected SensorCommonTests() {}
+
+    /**
+     * Abstract methods needed by concrete sensor classes to provide
+     */
+    protected abstract int getSensorType();
+    protected abstract int getMaxFrequencySupportedInuS();
+
+    /**
+     * Abstract test methods that sensors need to verify
+     */
+    public abstract void testEventValidity();
+    public abstract void testVarianceWhileStatic();
+
+    /**
+     * Methods to control the behavior of the tests by concrete sensor tests
+     */
+    protected int getWaitTimeoutInSeconds() {
+        return 30;
+    }
+
+    protected int getHighNumberOfIterationsToExecute() {
+        return 100;
+    }
+
+    protected int getLowNumberOfIterationsToExecute() {
+        return 10;
+    }
+
+    protected int getNumberOfThreadsToUse() {
+        return 5;
+    }
+
+    /**
+     * Test execution methods
+     */
+    @Override
+    protected void setUp() throws Exception {
+        PowerManager powerManager = (PowerManager) this.getContext().getSystemService(
+                Context.POWER_SERVICE);
+        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getLogTag());
+        mWakeLock.acquire();
+
+        mEventListener = new TestSensorListener();
+        mFlushListener = new TestFlushListener();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mSensorManager.unregisterListener(mEventListener, mSensorUnderTest);
+
+        mFlushListener = null;
+        mEventListener = null;
+        mSensorUnderTest = null;
+
+        releaseWakeLock();
+    }
+
+    @Override
+    public void runBare() throws Throwable {
+        mSensorManager = (SensorManager) this.getContext().getSystemService(Context.SENSOR_SERVICE);
+        assertNotNull("getSystemService#Sensor_Service", mSensorManager);
+
+        List<Sensor> availableSensors = mSensorManager.getSensorList(this.getSensorType());
+        // it is OK if there are no sensors available
+        for(Sensor sensor : availableSensors) {
+            mSensorUnderTest = sensor;
+            super.runBare();
+        }
+    }
+
+    /**
+     * Test cases continuous mode.
+     */
+    public void testCanRegisterListener() {
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                SensorManager.SENSOR_DELAY_NORMAL);
+        assertTrue("registerListener", result);
+    }
+
+    public void testNotTriggerSensor() {
+        TestTriggerListener listener = new TestTriggerListener();
+        assertFalse(
+                "requestTriggerSensor",
+                mSensorManager.requestTriggerSensor(listener, mSensorUnderTest));
+    }
+
+    public void testCanReceiveEvents() {
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                SensorManager.SENSOR_DELAY_NORMAL);
+        assertTrue("registerListener", result);
+        mEventListener.waitForEvents(5);
+    }
+
+    public void testMaxFrequency() {
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                this.getMaxFrequencySupportedInuS());
+        assertTrue("registerListener", result);
+    }
+
+    public void testEventsArriveInOrder() {
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                SensorManager.SENSOR_DELAY_FASTEST);
+        assertTrue("registerListener", result);
+        mEventListener.waitForEvents(100);
+
+        SensorEventForTest[] events = mEventListener.getAllEvents();
+        for(int i = 1; i < events.length; ++i) {
+            long previousTimestamp = events[i-1].getTimestamp();
+            long timestamp = events[i].getTimestamp();
+            assertTrue(
+                    String.format("[timestamp:%d] %d >= %d", i, previousTimestamp, timestamp),
+                    previousTimestamp < timestamp);
+        }
+    }
+
+    public void testStartStopRepeatedly() {
+        for(int i = 0; i < this.getLowNumberOfIterationsToExecute(); ++i) {
+            String iterationInfo = String.format("registerListener:%d", i);
+            boolean result = mSensorManager.registerListener(
+                    mEventListener,
+                    mSensorUnderTest,
+                    SensorManager.SENSOR_DELAY_FASTEST);
+            assertTrue(iterationInfo, result);
+            mEventListener.waitForEvents(1, iterationInfo);
+
+            mSensorManager.unregisterListener(mEventListener, mSensorUnderTest);
+        }
+    }
+
+    public void testUpdateRate() {
+        // the seed is constant for now, use a random seed when we can log the seed properly
+        final long seed = 0xABCDE012;
+        Random generator = new Random(seed);
+        for(int i = 0; i < this.getHighNumberOfIterationsToExecute(); ++i) {
+            int rate;
+            switch(generator.nextInt(5)) {
+                case 0:
+                    rate = SensorManager.SENSOR_DELAY_FASTEST;
+                    break;
+                case 1:
+                    rate = SensorManager.SENSOR_DELAY_GAME;
+                    break;
+                case 2:
+                    rate = SensorManager.SENSOR_DELAY_NORMAL;
+                    break;
+                case 3:
+                    rate = SensorManager.SENSOR_DELAY_UI;
+                    break;
+                case 4:
+                default:
+                    rate = this.getMaxFrequencySupportedInuS() * generator.nextInt(10);
+            }
+
+            String iterationInfo = String.format("registerListener:%d, rate:%d", i, rate);
+            assertTrue(
+                    iterationInfo,
+                    mSensorManager.registerListener(mEventListener, mSensorUnderTest, rate));
+
+            mEventListener.waitForEvents(generator.nextInt(5) + 1, iterationInfo);
+            mEventListener.clearEvents();
+
+            mSensorManager.unregisterListener(mEventListener, mSensorUnderTest);
+        }
+    }
+
+    public void testSeveralClients() throws InterruptedException {
+        ArrayList<Thread> threads = new ArrayList<Thread>();
+        for(int i = 0; i < this.getNumberOfThreadsToUse(); ++i) {
+            threads.add(new Thread() {
+                @Override
+                public void run() {
+                    testStartStopRepeatedly();
+                }
+            });
+        }
+
+        while(!threads.isEmpty()) {
+            Thread thread = threads.remove(0);
+            thread.join();
+        }
+    }
+
+    /**
+     * Test cases batching mode.
+     */
+    public void testRegisterForBatchingZeroReport() {
+        releaseWakeLock();
+
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                SensorManager.SENSOR_DELAY_NORMAL,
+                0 /*maxBatchReportLatencyUs*/,
+                0 /*reservedFlags*/,
+                mFlushListener);
+        assertTrue("registerListener", result);
+        mEventListener.waitForEvents(10);
+    }
+
+    public void testCanReceiveBatchEvents() {
+        releaseWakeLock();
+
+        // TODO: refactor out common code across tests that register for events and do post-process
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                SensorManager.SENSOR_DELAY_NORMAL,
+                5 * 1000000 /*maxBatchReportLatencyUs*/,
+                0 /*reservedFlags*/,
+                mFlushListener);
+        assertTrue("registerListener", result);
+        mEventListener.waitForEvents(10);
+    }
+
+    public void testBatchEventsArriveInOrder() {
+        releaseWakeLock();
+
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                SensorManager.SENSOR_DELAY_NORMAL,
+                5 * 1000000 /*maxBatchReportLatencyUs*/,
+                0 /*reservedFlags*/,
+                mFlushListener);
+        assertTrue("registerListener", result);
+        mEventListener.waitForEvents(100);
+
+        SensorEventForTest[] events = mEventListener.getAllEvents();
+        for(int i = 1; i < events.length; ++i) {
+            long previousTimestamp = events[i-1].getTimestamp();
+            long timestamp = events[i].getTimestamp();
+            assertTrue(
+                    String.format("[timestamp:%d] %d >= %d", i, previousTimestamp, timestamp),
+                    previousTimestamp < timestamp);
+        }
+    }
+
+    public void testStartStopBatchingRepeatedly() {
+        releaseWakeLock();
+
+        for(int i = 0; i < this.getLowNumberOfIterationsToExecute(); ++i) {
+            String iterationInfo = String.format("registerListener:%d", i);
+            boolean result = mSensorManager.registerListener(
+                    mEventListener,
+                    mSensorUnderTest,
+                    SensorManager.SENSOR_DELAY_FASTEST,
+                    5 * 1000000 /*maxBatchReportLatencyUs*/,
+                    0 /*reservedFlags*/,
+                    mFlushListener);
+
+            assertTrue(iterationInfo, result);
+            mEventListener.waitForEvents(5, iterationInfo);
+
+            mSensorManager.unregisterListener(mEventListener, mSensorUnderTest);
+        }
+    }
+
+    public void testUpdateBatchRate() {
+        releaseWakeLock();
+
+        // use a constant seed until it can be logged properly
+        final long seed = 0xFEDCBA98;
+        Random generator = new Random(seed);
+        for(int i = 0; i < this.getHighNumberOfIterationsToExecute(); ++i) {
+            int rate;
+            switch(generator.nextInt(5)) {
+                case 0:
+                    rate = SensorManager.SENSOR_DELAY_FASTEST;
+                    break;
+                case 1:
+                    rate = SensorManager.SENSOR_DELAY_GAME;
+                    break;
+                case 2:
+                    rate = SensorManager.SENSOR_DELAY_NORMAL;
+                    break;
+                case 3:
+                    rate = SensorManager.SENSOR_DELAY_UI;
+                    break;
+                case 4:
+                default:
+                    rate = this.getMaxFrequencySupportedInuS() * generator.nextInt(10);
+            }
+
+            String iterationInfo = String.format("registerListener:%d, rate:%d", i, rate);
+            boolean result = mSensorManager.registerListener(
+                    mEventListener,
+                    mSensorUnderTest,
+                    rate,
+                    generator.nextInt(5 * 1000000),
+                    0 /*reservedFlags*/,
+                    mFlushListener);
+            assertTrue(iterationInfo, result);
+
+            mEventListener.waitForEvents(generator.nextInt(5) + 1, iterationInfo);
+            mSensorManager.unregisterListener(mEventListener, mSensorUnderTest);
+            mEventListener.clearEvents();
+        }
+    }
+
+    public void testSeveralClientsBatching() {
+        ArrayList<Thread> threads = new ArrayList<Thread>();
+        for(int i = 0; i < this.getNumberOfThreadsToUse(); ++i) {
+            threads.add(new Thread() {
+                @Override
+                public void run() {
+                    testStartStopBatchingRepeatedly();
+                }
+            });
+        }
+
+        while(!threads.isEmpty()) {
+            Thread thread = threads.remove(0);
+            try {
+                thread.join();
+            } catch(InterruptedException e) {
+                // just continue
+            }
+        }
+    }
+
+    /**
+     * Tests for sensor characteristics.
+     */
+    public void testEventJittering() {
+        final long EXPECTED_TIMESTAMP_NS = this.getMaxFrequencySupportedInuS() * 1000;
+        final long THRESHOLD_IN_NS = EXPECTED_TIMESTAMP_NS / 10; // 10%
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                this.getMaxFrequencySupportedInuS());
+        assertTrue("registerListener", result);
+        mEventListener.waitForEvents(100);
+
+        SensorEventForTest[] events = mEventListener.getAllEvents();
+        ArrayList<Long> timestampDeltas = new ArrayList<Long>();
+        for(int i = 1; i < events.length; ++i) {
+            long previousTimestamp = events[i-1].getTimestamp();
+            long timestamp = events[i].getTimestamp();
+            long delta = timestamp - previousTimestamp;
+            long jitterValue = Math.abs(EXPECTED_TIMESTAMP_NS - delta);
+            timestampDeltas.add(jitterValue);
+        }
+
+        Collections.sort(timestampDeltas);
+        long percentile95InNs = timestampDeltas.get(95);
+        long actualPercentValue = (percentile95InNs * 100) / EXPECTED_TIMESTAMP_NS;
+
+        if(percentile95InNs > THRESHOLD_IN_NS) {
+            for(long jitter : timestampDeltas) {
+                Log.e(LOG_TAG, "Jittering delta: " + jitter);
+            }
+            String message = String.format(
+                    "95%%Jitter| 10%%:%dns, observed:%dns(%d%%)",
+                    THRESHOLD_IN_NS,
+                    percentile95InNs,
+                    actualPercentValue);
+            fail(message);
+        }
+    }
+
+    /**
+     * Private helpers.
+     */
+    private String getLogTag() {
+        return this.getClass().getSimpleName();
+    }
+
+    private void releaseWakeLock() {
+        PowerManager.WakeLock wakeLock = mWakeLock;
+        mWakeLock = null;
+
+        if(wakeLock != null) {
+            wakeLock.release();
+        }
+    }
+
+    private void collectBugreport() {
+        String commands[] = new String[] {
+                "dumpstate",
+                "dumpsys",
+                "logcat -d -v threadtime",
+                "exit"
+        };
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("M-d-y_H:m:s.S");
+        String outputFile = String.format(
+                "%s/%s_%s",
+                this.getLogTag(),
+                "/sdcard/Download",
+                dateFormat.format(new Date()));
+
+        DataOutputStream processOutput = null;
+        try {
+            Process process = Runtime.getRuntime().exec("/system/bin/sh -");
+            processOutput = new DataOutputStream(process.getOutputStream());
+
+            for(String command : commands) {
+                processOutput.writeBytes(String.format("%s >> %s\n", command, outputFile));
+            }
+
+            processOutput.flush();
+            process.waitFor();
+
+            Log.d(this.getLogTag(), String.format("Bug-Report collected at: %s", outputFile));
+        } catch (IOException e) {
+            fail("Unable to collect Bug Report. " + e.toString());
+        } catch (InterruptedException e) {
+            fail("Unable to collect Bug Report. " + e.toString());
+        } finally {
+            if(processOutput != null) {
+                try {
+                    processOutput.close();
+                } catch(IOException e) {}
+            }
+        }
+    }
+
+    /**
+     * Test method helper implementations
+     */
+    protected void validateSensorEvent(
+            float expectedX,
+            float expectedY,
+            float expectedZ,
+            float threshold) {
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                SensorManager.SENSOR_DELAY_FASTEST);
+
+        assertTrue("registerListener", result);
+        mEventListener.waitForEvents(1);
+        SensorEventForTest event = mEventListener.getLastEvent();
+
+        float xValue = event.getX();
+        assertTrue(
+                String.format("x-axis| expected:%f, actual:%f, threshold:%f", expectedX, xValue, threshold),
+                Math.abs(expectedX - xValue) <= threshold);
+
+        float yValue = event.getY();
+        assertTrue(
+                String.format("y-axis| expected:%f, actual:%f, threshold:%f", expectedY, yValue, threshold),
+                Math.abs(expectedY - yValue) <= threshold);
+
+        float zValue = event.getZ();
+        assertTrue(
+                String.format("z-axis| expected:%f, actual:%f, threshold:%f", expectedZ, zValue, threshold),
+                Math.abs(expectedZ - zValue) <= threshold);
+    }
+
+    protected void validateVarianceWhileStatic(
+            float referenceX,
+            float referenceY,
+            float referenceZ,
+            float threshold) {
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                this.getMaxFrequencySupportedInuS());
+        assertTrue("registerListener", result);
+        mEventListener.waitForEvents(100);
+
+        SensorEventForTest[] events = mEventListener.getAllEvents();
+        ArrayList<Float> deltaValuesX = new ArrayList<Float>();
+        ArrayList<Float> deltaValuesY = new ArrayList<Float>();
+        ArrayList<Float> deltaValuesZ = new ArrayList<Float>();
+        for(int i = 0; i < events.length; ++i) {
+            SensorEventForTest event = events[i];
+            deltaValuesX.add(Math.abs(event.getX() - referenceX));
+            deltaValuesY.add(Math.abs(event.getY() - referenceY));
+            deltaValuesZ.add(Math.abs(event.getZ() - referenceZ));
+        }
+
+        Collections.sort(deltaValuesX);
+        float percentile95X = deltaValuesX.get(95);
+        if(percentile95X > threshold) {
+            for(float valueX : deltaValuesX) {
+                Log.e(LOG_TAG, "Variance|X delta: " + valueX);
+            }
+            String message = String.format(
+                    "95%%Variance|X expected:%f, observed:%f",
+                    threshold,
+                    percentile95X);
+            fail(message);
+        }
+
+        Collections.sort(deltaValuesY);
+        float percentile95Y = deltaValuesY.get(95);
+        if(percentile95Y > threshold) {
+            for(float valueY : deltaValuesY) {
+                Log.e(LOG_TAG, "Variance|Y delta: " + valueY);
+            }
+            String message = String.format(
+                    "95%%Variance|Y expected:%f, observed:%f",
+                    threshold,
+                    percentile95Y);
+            fail(message);
+        }
+
+        Collections.sort(deltaValuesZ);
+        float percentile95Z = deltaValuesZ.get(95);
+        if(percentile95Z > threshold) {
+            for(float valueZ : deltaValuesZ) {
+                Log.e(LOG_TAG, "Variance|Z delta: " + valueZ);
+            }
+            String message = String.format(
+                    "95%%Variance|Z expected:%f, observed:%f",
+                    threshold,
+                    percentile95Z);
+            fail(message);
+        }
+    }
+
+    /**
+     * Private class definitions to support test of event handlers.
+     */
+    protected class SensorEventForTest {
+        private Sensor mSensor;
+        private long mTimestamp;
+        private int mAccuracy;
+
+        private float mValueX;
+        private float mValueY;
+        private float mValueZ;
+
+        public SensorEventForTest(SensorEvent event) {
+            mSensor = event.sensor;
+            mTimestamp = event.timestamp;
+            mAccuracy = event.accuracy;
+            mValueX = event.values[0];
+            mValueY = event.values[1];
+            mValueZ = event.values[2];
+        }
+
+        public Sensor getSensor() {
+            return mSensor;
+        }
+
+        public int getAccuracy() {
+            return mAccuracy;
+        }
+
+        public float getX() {
+            return mValueX;
+        }
+
+        public float getY() {
+            return mValueY;
+        }
+
+        public float getZ() {
+            return mValueZ;
+        }
+
+        public long getTimestamp() {
+            return mTimestamp;
+        }
+    }
+
+    protected class TestSensorListener implements SensorEventListener {
+        private final ConcurrentLinkedDeque<SensorEventForTest> mSensorEventsList =
+                new ConcurrentLinkedDeque<SensorEventForTest>();
+        private volatile CountDownLatch mEventLatch;
+
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            // copy the event because there is no better way to do this in the platform
+            mSensorEventsList.addLast(new SensorEventForTest(event));
+
+            CountDownLatch latch = mEventLatch;
+            if(latch != null) {
+                latch.countDown();
+            }
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        }
+
+        public void waitForEvents(int eventCount) {
+            waitForEvents(eventCount, null);
+        }
+
+        public void waitForEvents(int eventCount, String timeoutInfo) {
+            mEventLatch = new CountDownLatch(eventCount);
+            try {
+                boolean awaitCompleted = mEventLatch.await(getWaitTimeoutInSeconds(), TimeUnit.SECONDS);
+                if(!awaitCompleted) {
+                    collectBugreport();
+                }
+
+                String assertMessage = String.format(
+                        "WaitForEvents:%d, available:%d, %s",
+                        eventCount,
+                        mSensorEventsList.size(),
+                        timeoutInfo);
+                assertTrue(assertMessage, awaitCompleted);
+            } catch(InterruptedException e) { }
+        }
+
+        public SensorEventForTest getLastEvent() {
+            return mSensorEventsList.getLast();
+        }
+
+        public SensorEventForTest[] getAllEvents() {
+            return mSensorEventsList.toArray(new SensorEventForTest[0]);
+        }
+
+        public void clearEvents() {
+            mSensorEventsList.clear();
+        }
+    }
+
+    private class TestTriggerListener extends TriggerEventListener {
+        @Override
+        public void onTrigger(TriggerEvent event) {
+        }
+    }
+
+    private class TestFlushListener implements FlushCompleteListener {
+        @Override
+        public void onFlushCompleted(Sensor sensor) {
+        }
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorGyroscopeTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorGyroscopeTest.java
new file mode 100644
index 0000000..d3d72a3
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorGyroscopeTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.hardware.cts;
+
+import android.hardware.Sensor;
+
+public class SensorGyroscopeTest extends SensorCommonTests {
+    @Override
+    protected int getMaxFrequencySupportedInuS() {
+        return 10000; // 100Hz
+    }
+
+    @Override
+    protected int getSensorType() {
+        return Sensor.TYPE_GYROSCOPE;
+    }
+
+    @Override
+    public void testEventValidity() {
+        final float THRESHOLD = 0.1f; // dps
+        validateSensorEvent(
+                0 /*x-axis*/,
+                0 /*y-axis*/,
+                0 /*z-axis*/,
+                THRESHOLD);
+    }
+
+    @Override
+    public void testVarianceWhileStatic() {
+        final float THRESHOLD = 0.1f; // dps
+        validateVarianceWhileStatic(
+                0 /*x-axis*/,
+                0 /*y-axis*/,
+                0 /*z-axis*/,
+                THRESHOLD);
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorMagneticFieldTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorMagneticFieldTest.java
new file mode 100644
index 0000000..10cabb8
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorMagneticFieldTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.hardware.cts;
+
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class SensorMagneticFieldTest extends SensorCommonTests {
+    @Override
+    protected int getMaxFrequencySupportedInuS() {
+        return 100000; // 10Hz
+    }
+
+    @Override
+    protected int getSensorType() {
+        return Sensor.TYPE_MAGNETIC_FIELD;
+    }
+
+    @Override
+    public void testEventValidity() {
+        validateSensorEvent(
+                0 /*x-axis*/,
+                0 /*y-axis*/,
+                0 /*z-axis*/,
+                SensorManager.MAGNETIC_FIELD_EARTH_MAX);
+    }
+
+    @Override
+    public void testVarianceWhileStatic() {
+        float THRESHOLD_IN_UT = SensorManager.MAGNETIC_FIELD_EARTH_MAX / 10;
+        boolean result = mSensorManager.registerListener(
+                mEventListener,
+                mSensorUnderTest,
+                this.getMaxFrequencySupportedInuS());
+        assertTrue("registerListener", result);
+        mEventListener.waitForEvents(100);
+
+        SensorEventForTest[] events = mEventListener.getAllEvents();
+        ArrayList<Float> deltaValuesX = new ArrayList<Float>();
+        ArrayList<Float> deltaValuesY = new ArrayList<Float>();
+        ArrayList<Float> deltaValuesZ = new ArrayList<Float>();
+        for(int i = 1; i < events.length; ++i) {
+            SensorEventForTest previousEvent = events[i-1];
+            SensorEventForTest event = events[i];
+
+            deltaValuesX.add(Math.abs(event.getX() - previousEvent.getX()));
+            deltaValuesY.add(Math.abs(event.getY() - previousEvent.getY()));
+            deltaValuesZ.add(Math.abs(event.getZ() - previousEvent.getZ()));
+        }
+
+        Collections.sort(deltaValuesX);
+        float percentile95X = deltaValuesX.get(95);
+        if(percentile95X > THRESHOLD_IN_UT) {
+            for(float valueX : deltaValuesX) {
+                Log.e(LOG_TAG, "Variance|X delta: " + valueX);
+            }
+            String message = String.format(
+                    "95%%Variance|X expected:%f, observed:%f",
+                    THRESHOLD_IN_UT,
+                    percentile95X);
+            fail(message);
+        }
+
+        Collections.sort(deltaValuesY);
+        float percentile95Y = deltaValuesY.get(95);
+        if(percentile95Y > THRESHOLD_IN_UT) {
+            for(float valueY : deltaValuesY) {
+                Log.e(LOG_TAG, "Variance|Y delta: " + valueY);
+            }
+            String message = String.format(
+                    "95%%Variance|Y expected:%f, observed:%f",
+                    THRESHOLD_IN_UT,
+                    percentile95Y);
+            fail(message);
+        }
+
+        Collections.sort(deltaValuesZ);
+        float percentile95Z = deltaValuesZ.get(95);
+        if(percentile95Z > THRESHOLD_IN_UT) {
+            for(float valueZ : deltaValuesZ) {
+                Log.e(LOG_TAG, "Variance|Z delta: " + valueZ);
+            }
+            String message = String.format(
+                    "95%%Variance|Z expected:%f, observed:%f",
+                    THRESHOLD_IN_UT,
+                    percentile95Z);
+            fail(message);
+        }
+    }
+}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
new file mode 100644
index 0000000..a7ee974
--- /dev/null
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.webkit.cts;
+
+
+import android.content.Context;
+import android.cts.util.PollingCheck;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.util.Log;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
+import android.webkit.WebView;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class WebViewStartupTest
+        extends ActivityInstrumentationTestCase2<WebViewStartupStubActivity> {
+
+    private static final int TEST_TIMEOUT = 5000;
+    private static final String TAG = "WebViewStartupTest";
+
+    private WebViewStartupStubActivity mActivity;
+
+    public WebViewStartupTest() {
+        super("com.android.cts.stub", WebViewStartupStubActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        mActivity = getActivity();
+    }
+
+    @UiThreadTest
+    public void testCookieManagerBlockingUiThread() throws Throwable {
+        CtsTestServer server = new CtsTestServer(mActivity, false);
+        final String url = server.getCookieUrl("death.html");
+
+        Thread background = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                CookieSyncManager csm = CookieSyncManager.createInstance(mActivity);
+                CookieManager cookieManager = CookieManager.getInstance();
+
+                cookieManager.removeAllCookie();
+                cookieManager.setAcceptCookie(true);
+                cookieManager.setCookie(url, "count=41");
+                Log.i(TAG, "done setting cookie before creating webview");
+            }
+        });
+        background.start();
+        background.join();
+
+        // Now create WebView and test that setting the cookie beforehand really worked.
+        mActivity.createAndAttachWebView();
+        WebViewOnUiThread onUiThread = new WebViewOnUiThread(this, mActivity.getWebView());
+        onUiThread.loadUrlAndWaitForCompletion(url);
+        assertEquals("1|count=41", onUiThread.getTitle()); // outgoing cookie
+        CookieManager cookieManager = CookieManager.getInstance();
+        String cookie = cookieManager.getCookie(url);
+        assertNotNull(cookie);
+        final Pattern pat = Pattern.compile("count=(\\d+)");
+        Matcher m = pat.matcher(cookie);
+        assertTrue(m.matches());
+        assertEquals("42", m.group(1)); // value got incremented
+    }
+
+}