Merge remote branch 'goog/honeycomb' into manualmerge
diff --git a/CtsTestCoverage.mk b/CtsTestCoverage.mk
index 7053fea..588c8f5 100644
--- a/CtsTestCoverage.mk
+++ b/CtsTestCoverage.mk
@@ -60,6 +60,8 @@
 	$(hide) echo $(1): file://$(ANDROID_BUILD_TOP)/$(COVERAGE_OUT)/$(4)
 endef
 
+# classes.dex is stripped from package.apk if dex-preopt is enabled,
+# so we use the copy that definitely includes classes.dex.
 define add-testcase-apk
-	TEST_APKS += $(call intermediates-dir-for,APPS,$(1))/package.apk
+	TEST_APKS += $(call intermediates-dir-for,APPS,$(1))/package.apk.unaligned
 endef
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index bbf7eaf..1a39fd3 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -37,4 +37,30 @@
 	adb install -r $(ANDROID_PRODUCT_OUT)/data/app/CtsVerifier.apk \
 		&& adb shell "am start -n com.android.cts.verifier/.CtsVerifierActivity"
 
+#
+# Creates a "cts-verifier" directory that will contain:
+#
+# 1. Out directory with a "android-cts-verifier" containing the CTS Verifier
+#    and other binaries it needs.
+#
+# 2. Zipped version of the android-cts-verifier directory to be included with
+#    the build distribution.
+#
+cts-dir := $(HOST_OUT)/cts-verifier
+verifier-dir-name := android-cts-verifier
+verifier-dir := $(cts-dir)/$(verifier-dir-name)
+verifier-zip-name := $(verifier-dir-name).zip
+verifier-zip := $(cts-dir)/$(verifier-zip-name)
+
+cts : $(verifier-zip)
+$(verifier-zip) : CtsVerifier $(ACP)
+		$(hide) mkdir -p $(verifier-dir)
+		$(hide) $(ACP) -fp $(call intermediates-dir-for,APPS,CtsVerifier)/package.apk \
+				$(verifier-dir)/CtsVerifier.apk
+		$(hide) cd $(cts-dir) && zip -rq $(verifier-dir-name) $(verifier-dir-name)
+
+ifneq ($(filter cts, $(MAKECMDGOALS)),)
+  $(call dist-for-goals, cts, $(verifier-zip):$(verifier-zip-name))
+endif
+
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index f956c5c..50afe4b 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -182,6 +182,15 @@
             <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
         </activity>
 
+        <activity android:name=".sensors.GyroscopeTestActivity" android:label="@string/snsr_gyro_test"
+                android:screenOrientation="nosensor">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
+        </activity>
+
         <activity android:name=".audioquality.AudioQualityVerifierActivity"
                 android:label="@string/aq_verifier">
             <intent-filter>
diff --git a/apps/CtsVerifier/res/drawable/gray_bubble.xml b/apps/CtsVerifier/res/drawable/gray_bubble.xml
new file mode 100644
index 0000000..66eda76
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable/gray_bubble.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+  <solid android:color="#333333" />
+  <stroke android:width="2dip" android:color="#666666" />
+  <corners android:radius="10dip"/>
+</shape>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/snsr_gyro.xml b/apps/CtsVerifier/res/layout/snsr_gyro.xml
new file mode 100644
index 0000000..d4d7000
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/snsr_gyro.xml
@@ -0,0 +1,62 @@
+<?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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <include android:id="@+id/pass_fail_buttons"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            layout="@layout/pass_fail_buttons" />
+
+    <android.opengl.GLSurfaceView android:id="@+id/gl_surface_view"
+            android:layout_alignParentTop="true"
+            android:layout_above="@+id/pass_fail_buttons"
+            android:layout_marginBottom="5dip"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    <TextView android:id="@+id/sensor_value"
+            android:background="@drawable/gray_bubble"
+            android:drawablePadding="10dip"
+            android:layout_above="@+id/pass_fail_buttons"
+            android:layout_centerInParent="true"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="10dip"
+            android:paddingLeft="10dip"
+            android:paddingRight="10dip"
+            android:paddingTop="5dip"
+            android:paddingBottom="5dip"
+            android:textSize="28dip"
+            />
+
+    <TextView android:id="@+id/progress"
+            android:background="@drawable/gray_bubble"
+            android:layout_alignParentTop="true"
+            android:layout_centerInParent="true"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dip"
+            android:paddingLeft="10dip"
+            android:paddingRight="10dip"
+            android:paddingTop="5dip"
+            android:paddingBottom="5dip"
+            android:textSize="28dip"
+            />
+    
+</RelativeLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/menu/test_list_menu.xml b/apps/CtsVerifier/res/menu/test_list_menu.xml
index 67c626c..495e36f 100644
--- a/apps/CtsVerifier/res/menu/test_list_menu.xml
+++ b/apps/CtsVerifier/res/menu/test_list_menu.xml
@@ -6,7 +6,7 @@
     <item android:id="@+id/copy"
           android:icon="@android:drawable/ic_menu_upload"
           android:title="@string/copy" />
-    <item android:id="@+id/share"
+    <item android:id="@+id/export"
           android:icon="@android:drawable/ic_menu_share"
-          android:title="@string/share" />
+          android:title="@string/export" />
 </menu>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/colors.xml b/apps/CtsVerifier/res/values/colors.xml
new file mode 100644
index 0000000..220ba29
--- /dev/null
+++ b/apps/CtsVerifier/res/values/colors.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 
+**
+** Copyright 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>
+    <color name="green">#00FF00</color>
+    <color name="red">#FF0000</color>
+</resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 36364a3..4db9d26 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -40,9 +40,10 @@
     <string name="test_results_cleared">Test results cleared.</string>
     <string name="copy">Copy</string>
     <string name="test_results_copied">Test results copied to clipboard.</string>
-    <string name="share">Share</string>
-    <string name="share_test_results">Share Test Results</string>
     <string name="test_results_error">Couldn\'t create test results report.</string>
+    <string name="export">Export</string>
+    <string name="no_storage">Cannot save report to external storage, see log for details.</string>
+    <string name="report_saved">Report saved to: %s</string>
 
     <!-- Strings for Device Administration tests -->
     <string name="da_policy_serialization_test">Policy Serialization Test</string>
@@ -140,11 +141,17 @@
 
     <string name="empty"></string>
 
-    <!-- Strings for AccelerometerTestActivity and MagnetometerTestActivity -->
+    <!-- Strings for AccelerometerTestActivity and GyroscopeTestActivity -->
     <string name="snsr_accel_test">Accelerometer Test</string>
     <string name="snsr_accel_test_info">This test verifies that the accelerometer is working properly. As you move the device around through space, the triangle should always point down (i.e. in the direction of gravity.) If it does not, the accelerometer is improperly configured.</string>
-    <string name="snsr_mag_test">Magnetometer Test</string>
-    <string name="snsr_mag_test_info">This test verifies that the magnetometer (compass) is working properly. As you move the device around through space, the triangle should always point toward the north pole (which may point through the ground.) If it does not, the magnetometer is improperly configured. Be sure not to run this test with the device near any strong magnetic field generators.</string>
+
+    <string name="snsr_gyro_test">Gyroscope Test</string>
+    <string name="snsr_gyro_test_info">This test verifies that the gyroscope is working properly.\n\nRotate your device as shown by the 3D block. A green background or a check mark indicates that the gyroscope\'s value is correct. A red background or a X mark indicates that the gyroscope\'s value is not right.\n\nThere are 6 parts of the test corresponding to each rotation. Press Pass for all the stages to complete this test.</string>
+    <string name="snsr_gyro_test_progress">Test %1$d of %2$d</string>
+    <string name="snsr_gyro_test_no_gyro_title">No gyroscope?</string>
+    <string name="snsr_gyro_test_no_gyro_message">It doesn\'t seem like you have a gyroscope, so you don\'t need to run this test.</string>
+    <string name="snsr_gyro_test_degrees_title">Wrong units?</string>
+    <string name="snsr_gyro_test_degrees_message">These values looks like degrees per second. These should be radians per second!</string>
 
     <!-- Strings for SuidFilesActivity -->
     <string name="suid_files">SUID File Scanner</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
new file mode 100644
index 0000000..f7db56d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.widget.Toast;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Background task to generate a report and save it to external storage.
+ */
+class ReportExporter extends AsyncTask<Void, Void, String> {
+    protected static final Logger LOG = Logger.getLogger(ReportExporter.class.getName());
+
+    private final Context mContext;
+    private final TestListAdapter mAdapter;
+
+    ReportExporter(Context context, TestListAdapter adapter) {
+        this.mContext = context;
+        this.mAdapter = adapter;
+    }
+
+    @Override
+    protected String doInBackground(Void... params) {
+        if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
+            LOG.log(Level.WARNING, "External storage is not writable.");
+            return mContext.getString(R.string.no_storage);
+        }
+        byte[] contents;
+        try {
+            TestResultsReport report = new TestResultsReport(mContext, mAdapter);
+            contents = report.getContents().getBytes();
+        } catch (Exception e) {
+            LOG.log(Level.WARNING, "Couldn't create test results report", e);
+            return mContext.getString(R.string.test_results_error);
+        }
+        File reportPath = new File(Environment.getExternalStorageDirectory(), "ctsVerifierReports");
+        reportPath.mkdirs();
+        File reportFile = new File(reportPath,
+                "ctsVerifierReport-" + System.currentTimeMillis() + ".zip");
+        ZipOutputStream out = null;
+        try {
+            out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(reportFile)));
+            ZipEntry entry = new ZipEntry("ctsVerifierReport.xml");
+            out.putNextEntry(entry);
+            out.write(contents);
+        } catch (IOException e) {
+            LOG.log(Level.WARNING, "I/O exception writing report to storage.", e);
+            return mContext.getString(R.string.no_storage);
+        } finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+            } catch (IOException e) {
+                LOG.log(Level.WARNING, "I/O exception closing report.", e);
+            }
+        }
+
+        return mContext.getString(R.string.report_saved, reportFile.getPath());
+    }
+
+    @Override
+    protected void onPostExecute(String result) {
+        Toast.makeText(mContext, result, Toast.LENGTH_LONG).show();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
index fe41583..bc7a2b0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
@@ -100,8 +100,8 @@
                 handleCopyItemSelected();
                 return true;
 
-            case R.id.share:
-                handleShareItemSelected();
+            case R.id.export:
+                handleExportItemSelected();
                 return true;
 
             default:
@@ -119,25 +119,15 @@
             TestResultsReport report = new TestResultsReport(this, mAdapter);
             ClipboardManager clipboardManager = (ClipboardManager)
                     getSystemService(CLIPBOARD_SERVICE);
-            clipboardManager.setText(report.getBody());
+            clipboardManager.setText(report.getContents());
             Toast.makeText(this, R.string.test_results_copied, Toast.LENGTH_SHORT).show();
         } catch (IOException e) {
             Toast.makeText(this, R.string.test_results_error, Toast.LENGTH_SHORT).show();
-            Log.e(TAG, "Coudn't copy test results report", e);
+            Log.e(TAG, "Couldn't copy test results report", e);
         }
     }
 
-    private void handleShareItemSelected() {
-        try {
-            Intent target = new Intent(Intent.ACTION_SEND);
-            TestResultsReport report = new TestResultsReport(this, mAdapter);
-            target.setType(report.getType());
-            target.putExtra(Intent.EXTRA_SUBJECT, report.getSubject());
-            target.putExtra(Intent.EXTRA_TEXT, report.getBody());
-            startActivity(Intent.createChooser(target, getString(R.string.share_test_results)));
-        } catch (IOException e) {
-            Toast.makeText(this, R.string.test_results_error, Toast.LENGTH_SHORT).show();
-            Log.e(TAG, "Coudn't share test results report", e);
-        }
+    private void handleExportItemSelected() {
+        new ReportExporter(this, mAdapter).execute();
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index c7af68a..37d4819 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -77,17 +77,7 @@
         this.mAdapter = adapter;
     }
 
-    String getType() {
-        return "application/xml";
-    }
-
-    String getSubject() {
-        return mContext.getString(R.string.subject_header,
-                Version.getVersionName(mContext),
-                Build.FINGERPRINT);
-    }
-
-    String getBody() throws IllegalArgumentException, IllegalStateException, IOException {
+    String getContents() throws IllegalArgumentException, IllegalStateException, IOException {
         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
 
         XmlSerializer xml = Xml.newSerializer();
@@ -106,7 +96,16 @@
 
         xml.startTag(null, DEVICE_INFO_TAG);
         xml.startTag(null, BUILD_INFO_TAG);
+        xml.attribute(null, "board", Build.BOARD);
+        xml.attribute(null, "brand", Build.BRAND);
+        xml.attribute(null, "device", Build.DEVICE);
+        xml.attribute(null, "display", Build.DISPLAY);
         xml.attribute(null, "fingerprint", Build.FINGERPRINT);
+        xml.attribute(null, "id", Build.ID);
+        xml.attribute(null, "model", Build.MODEL);
+        xml.attribute(null, "product", Build.PRODUCT);
+        xml.attribute(null, "release", Build.VERSION.RELEASE);
+        xml.attribute(null, "sdk", Build.VERSION.SDK);
         xml.endTag(null, BUILD_INFO_TAG);
         xml.endTag(null, DEVICE_INFO_TAG);
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeTestActivity.java
new file mode 100644
index 0000000..ea6ca4c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeTestActivity.java
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.sensors;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLU;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Manual test for testing the gyroscope sensor. This test consists of 6 steps for all the
+ * different ways to rotate the device along the x, y, and z axis. It also raises a warning
+ * if the values seem to high and may be degrees.
+ */
+public class GyroscopeTestActivity extends PassFailButtons.Activity {
+
+    private static final int NUM_STAGES = 6;
+    private static final String STAGE_INDEX_EXTRA = "stageIndex";
+
+    private static final int BACKGROUND_BLACK = 0;
+    private static final int BACKGROUND_RED = 1;
+    private static final int BACKGROUND_GREEN = 2;
+
+    private AtomicInteger mBackgroundColor = new AtomicInteger(BACKGROUND_BLACK);
+
+    private SensorManager mSensorManager;
+    private Sensor mSensor;
+    private SensorListener mSensorListener;
+    private GLSurfaceView mGLSurfaceView;
+    private TextView mProgressText;
+    private TextView mSensorText;
+
+    private AlertDialog mNoGyroscopeWarningDialog;
+    private AlertDialog mDegreesWarningDialog;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.snsr_gyro);
+        setInfoResources(R.string.snsr_gyro_test, R.string.snsr_gyro_test_info, 0);
+        setPassFailButtonClickListeners();
+
+        // This activity is reused 6 times with different settings to test each rotation direction
+        final int stageIndex = getIntent().getIntExtra(STAGE_INDEX_EXTRA, 0);
+        Settings settings = getSettings(stageIndex);
+
+        // Hitting the pass button goes to the next test activity. Only the last one ends the test.
+        if (stageIndex + 1 < NUM_STAGES) {
+            setPassButtonGoesToNextStage(stageIndex);
+        }
+
+        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
+        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
+        mSensorListener = new SensorListener(settings.mSensorEventIndex,
+                settings.mExpectPositiveValue);
+
+        mGLSurfaceView = (GLSurfaceView) findViewById(R.id.gl_surface_view);
+        mGLSurfaceView.setRenderer(new RotationGuideRenderer(settings.mRotateX, settings.mRotateY,
+                settings.mRotateZ));
+
+        mProgressText = (TextView) findViewById(R.id.progress);
+        mProgressText.setText(String.format(getString(R.string.snsr_gyro_test_progress),
+                settings.mStageIndex + 1, settings.mTotalStages));
+
+        mSensorText = (TextView) findViewById(R.id.sensor_value);
+    }
+
+    private Settings getSettings(int stageIndex) {
+        switch (stageIndex) {
+            case 0:
+                return new Settings(stageIndex, NUM_STAGES, 0, 0, 1, 2, true);
+            case 1:
+                return new Settings(stageIndex, NUM_STAGES, 0, 0, -1, 2, false);
+            case 2:
+                return new Settings(stageIndex, NUM_STAGES, 0, 1, 0, 1, true);
+            case 3:
+                return new Settings(stageIndex, NUM_STAGES, 0, -1, 0, 1, false);
+            case 4:
+                return new Settings(stageIndex, NUM_STAGES, 1, 0, 0, 0, true);
+            case 5:
+                return new Settings(stageIndex, NUM_STAGES, -1, 0, 0, 0, false);
+            default:
+                throw new IllegalArgumentException("Bad stage index: " + stageIndex);
+        }
+    }
+
+    /** Bundle of settings for testing a certain rotation direction. */
+    class Settings {
+        int mStageIndex;
+        int mTotalStages;
+        float mRotateX;
+        float mRotateY;
+        float mRotateZ;
+        int mSensorEventIndex;
+        boolean mExpectPositiveValue;
+
+        Settings(int stageIndex, int totalStages, float rotateX, float rotateY, float rotateZ,
+                int sensorEventIndex, boolean expectPositiveValue) {
+            mStageIndex = stageIndex;
+            mTotalStages = totalStages;
+            mRotateX = rotateX;
+            mRotateY = rotateY;
+            mRotateZ = rotateZ;
+            mSensorEventIndex = sensorEventIndex;
+            mExpectPositiveValue = expectPositiveValue;
+        }
+    }
+
+    private void setPassButtonGoesToNextStage(final int stageIndex) {
+        findViewById(R.id.pass_button).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(GyroscopeTestActivity.this,
+                        GyroscopeTestActivity.class);
+                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
+                        | Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+                intent.putExtra(STAGE_INDEX_EXTRA, stageIndex + 1);
+                startActivity(intent);
+            }
+        });
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (!mSensorManager.registerListener(mSensorListener, mSensor,
+                SensorManager.SENSOR_DELAY_UI)) {
+            showNoGyroscopeWarningDialog();
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mSensorManager.unregisterListener(mSensorListener, mSensor);
+    }
+
+    /** Renders a spinning block to indicate how the device should be rotated in the test. */
+    class RotationGuideRenderer implements GLSurfaceView.Renderer {
+
+        private static final double ANGLE_INCREMENT = 1.0;
+
+        private final Monolith mMonolith = new Monolith();
+
+        private float mAngle = 0.0f;
+
+        private float mRotateX;
+
+        private float mRotateY;
+
+        private float mRotateZ;
+
+        public RotationGuideRenderer(float rotateX, float rotateY, float rotateZ) {
+            mRotateX = rotateX;
+            mRotateY = rotateY;
+            mRotateZ = rotateZ;
+        }
+
+        @Override
+        public void onDrawFrame(GL10 gl) {
+            clearBackground(gl);
+            gl.glMatrixMode(GL10.GL_MODELVIEW);
+            gl.glLoadIdentity();
+            gl.glRotatef(mAngle, mRotateX, mRotateY, mRotateZ);
+            mMonolith.draw(gl);
+            mAngle += ANGLE_INCREMENT;
+        }
+
+        private void clearBackground(GL10 gl) {
+            switch (mBackgroundColor.get()) {
+                case BACKGROUND_GREEN:
+                    gl.glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+                    break;
+
+                case BACKGROUND_RED:
+                    gl.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+                    break;
+
+                default:
+                    gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+                    break;
+            }
+            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+        }
+
+        @Override
+        public void onSurfaceChanged(GL10 gl, int width, int height) {
+            gl.glViewport(0, 0, width, height);
+            gl.glMatrixMode(GL10.GL_PROJECTION);
+            gl.glLoadIdentity();
+            float ratio = (float) width / height;
+            gl.glFrustumf(-ratio, ratio, -1, 1, 3, 15);
+            GLU.gluLookAt(gl, 0, 0, 10, 0, 0, 0, 0, 1, 0);
+        }
+
+        @Override
+        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+            gl.glEnable(GL10.GL_LIGHTING);
+            gl.glEnable(GL10.GL_LIGHT0);
+            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, new float[] {0.75f, 0.75f, 0.75f, 1f}, 0);
+        }
+    }
+
+    /** Rectangular block that is rotated by {@link RotationGuideRenderer}. */
+    class Monolith {
+
+        private static final int NUM_VERTICES = 8;
+
+        private static final int NUM_INDICES = 36;
+
+        private FloatBuffer mVertexBuffer;
+
+        private ShortBuffer mIndexBuffer;
+
+        public Monolith() {
+            mVertexBuffer = ByteBuffer.allocateDirect(NUM_VERTICES * 3 * 4)
+                    .order(ByteOrder.nativeOrder())
+                    .asFloatBuffer();
+
+            float[] coordinates = {
+                    -0.65f, -1, 0.2f,
+                    -0.65f, 1, 0.2f,
+                    0.65f, 1, 0.2f,
+                    0.65f, -1, 0.2f,
+
+                    -0.65f, -1, -0.2f,
+                    -0.65f, 1, -0.2f,
+                    0.65f, 1, -0.2f,
+                    0.65f, -1, -0.2f,
+            };
+
+            for (int i = 0; i < coordinates.length; i++) {
+                mVertexBuffer.put(coordinates[i]);
+            }
+
+            mIndexBuffer = ByteBuffer.allocateDirect(NUM_INDICES * 2)
+                    .order(ByteOrder.nativeOrder())
+                    .asShortBuffer();
+
+            // Front
+            mIndexBuffer.put((short) 0);
+            mIndexBuffer.put((short) 1);
+            mIndexBuffer.put((short) 2);
+            mIndexBuffer.put((short) 0);
+            mIndexBuffer.put((short) 2);
+            mIndexBuffer.put((short) 3);
+
+            // Back
+            mIndexBuffer.put((short) 7);
+            mIndexBuffer.put((short) 6);
+            mIndexBuffer.put((short) 5);
+            mIndexBuffer.put((short) 7);
+            mIndexBuffer.put((short) 5);
+            mIndexBuffer.put((short) 4);
+
+            // Right
+            mIndexBuffer.put((short) 3);
+            mIndexBuffer.put((short) 2);
+            mIndexBuffer.put((short) 6);
+            mIndexBuffer.put((short) 3);
+            mIndexBuffer.put((short) 6);
+            mIndexBuffer.put((short) 7);
+
+            // Left
+            mIndexBuffer.put((short) 4);
+            mIndexBuffer.put((short) 5);
+            mIndexBuffer.put((short) 1);
+            mIndexBuffer.put((short) 4);
+            mIndexBuffer.put((short) 1);
+            mIndexBuffer.put((short) 0);
+
+            // Top
+            mIndexBuffer.put((short) 1);
+            mIndexBuffer.put((short) 5);
+            mIndexBuffer.put((short) 6);
+            mIndexBuffer.put((short) 1);
+            mIndexBuffer.put((short) 6);
+            mIndexBuffer.put((short) 2);
+
+            // Bottom
+            mIndexBuffer.put((short) 3);
+            mIndexBuffer.put((short) 7);
+            mIndexBuffer.put((short) 4);
+            mIndexBuffer.put((short) 3);
+            mIndexBuffer.put((short) 4);
+            mIndexBuffer.put((short) 0);
+
+            mVertexBuffer.position(0);
+            mIndexBuffer.position(0);
+        }
+
+        public void draw(GL10 gl) {
+            gl.glColor4f(0.5f, 0.5f, 0.5f, 1f);
+            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
+            gl.glDrawElements(GL10.GL_TRIANGLES, NUM_INDICES, GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
+        }
+    }
+
+    class SensorListener implements SensorEventListener {
+
+        /** Throw away other events that are smaller than this. */
+        private static final double MOVING_AMOUNT = 0.1;
+
+        private final int mEventIndex;
+
+        private final boolean mExpectPositive;
+
+        SensorListener(int eventIndex, boolean expectPositive) {
+            mEventIndex = eventIndex;
+            mExpectPositive = expectPositive;
+        }
+
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            float value = event.values[mEventIndex];
+            if (value > MOVING_AMOUNT) {
+                if (mExpectPositive) {
+                    updateWidgets(value, BACKGROUND_GREEN, R.drawable.fs_good);
+                } else {
+                    updateWidgets(value, BACKGROUND_RED, R.drawable.fs_error);
+                }
+            } else if (value < -MOVING_AMOUNT) {
+                if (mExpectPositive) {
+                    updateWidgets(value, BACKGROUND_RED, R.drawable.fs_error);
+                } else {
+                    updateWidgets(value, BACKGROUND_GREEN, R.drawable.fs_good);
+                }
+            } else {
+                updateWidgets(value, BACKGROUND_BLACK, R.drawable.fs_indeterminate);
+            }
+
+            if (value > 10) {
+                showDegreesWarningDialog();
+            }
+        }
+
+        void updateWidgets(float sensorValue, int backgroundColor, int icon) {
+            synchronized (GyroscopeTestActivity.this) {
+                mBackgroundColor.set(backgroundColor);
+            }
+            mSensorText.setText(String.format("%+.2f", sensorValue));
+            mSensorText.setCompoundDrawablesWithIntrinsicBounds(0, 0, icon, 0);
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        }
+    }
+
+    private void showNoGyroscopeWarningDialog() {
+        if (mNoGyroscopeWarningDialog == null) {
+            mNoGyroscopeWarningDialog = new AlertDialog.Builder(GyroscopeTestActivity.this)
+                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setTitle(R.string.snsr_gyro_test_no_gyro_title)
+                .setMessage(R.string.snsr_gyro_test_no_gyro_message)
+                .setPositiveButton(android.R.string.ok, null)
+                .create();
+        }
+        if (!mNoGyroscopeWarningDialog.isShowing()) {
+            mNoGyroscopeWarningDialog.show();
+        }
+    }
+
+    private void showDegreesWarningDialog() {
+        if (mDegreesWarningDialog == null) {
+            mDegreesWarningDialog = new AlertDialog.Builder(GyroscopeTestActivity.this)
+                    .setIcon(android.R.drawable.ic_dialog_alert)
+                    .setTitle(R.string.snsr_gyro_test_degrees_title)
+                    .setMessage(R.string.snsr_gyro_test_degrees_message)
+                    .setPositiveButton(android.R.string.ok, null)
+                    .create();
+        }
+        if (!mDegreesWarningDialog.isShowing()) {
+            mDegreesWarningDialog.show();
+        }
+    }
+}
diff --git a/development/ide/eclipse/.classpath b/development/ide/eclipse/.classpath
index 8061867..7375ad8 100644
--- a/development/ide/eclipse/.classpath
+++ b/development/ide/eclipse/.classpath
@@ -11,6 +11,7 @@
     <classpathentry kind="src" path="cts/tests/SignatureTest/tests/src"/>
     <classpathentry kind="src" path="cts/tests/accessibilityservice/src"/>
     <classpathentry kind="src" path="cts/tests/appsecurity-tests/src"/>
+    <classpathentry kind="src" path="cts/tests/appsecurity-tests/test-apps/AppWithData/src"/>
     <classpathentry kind="src" path="cts/tests/core/runner/src"/>
     <classpathentry kind="src" path="cts/tests/deviceadmin/src"/>
     <classpathentry kind="src" path="cts/tests/src"/>
diff --git a/tests/appsecurity-tests/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java b/tests/appsecurity-tests/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
index d77a872..1de6464 100644
--- a/tests/appsecurity-tests/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
+++ b/tests/appsecurity-tests/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
@@ -16,12 +16,17 @@
 
 package com.android.cts.appwithdata;
 
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.test.AndroidTestCase;
+
 import java.io.FileOutputStream;
 import java.io.IOException;
 
-import android.content.Context;
-import android.test.AndroidTestCase;
-
 /**
  * Test that will create private app data.
  *
@@ -35,6 +40,14 @@
      */
     private static final String PRIVATE_FILE_NAME = "private_file.txt";
 
+    private static final String PREFERENCES_FILE_NAME = "preferences";
+    private static final String PREFERENCE_KEY = "preference_key";
+    private static final String PREFERENCE_VALUE = "preference_value";
+
+    static final String DB_TABLE_NAME = "test_table";
+    static final String DB_COLUMN = "test_column";
+    static final String DB_VALUE = "test_value";
+
     /**
      * Creates a file private to this app
      * @throws IOException if any error occurred when creating the file
@@ -45,6 +58,39 @@
         outputStream.write("file contents".getBytes());
         outputStream.close();
         assertTrue(getContext().getFileStreamPath(PRIVATE_FILE_NAME).exists());
+
+        writeToPreferences();
+        writeToDatabase();
+    }
+
+    private void writeToPreferences() {
+        SharedPreferences prefs = mContext.getSharedPreferences(PREFERENCES_FILE_NAME, 0);
+        SharedPreferences.Editor editor = prefs.edit();
+        editor.putString(PREFERENCE_KEY, PREFERENCE_VALUE);
+        editor.commit();
+        assertEquals(PREFERENCE_VALUE, prefs.getString(PREFERENCE_KEY, null));
+    }
+
+    private void writeToDatabase() {
+        SQLiteDatabase db = null;
+        Cursor cursor = null;
+        try {
+            db = new TestDatabaseOpenHelper(mContext).getWritableDatabase();
+            ContentValues values = new ContentValues(1);
+            values.put(DB_COLUMN, DB_VALUE);
+            assertTrue(db.insert(DB_TABLE_NAME, null, values) != -1);
+
+            cursor = db.query(DB_TABLE_NAME, new String[] {DB_COLUMN},
+                    null, null, null, null, null);
+            assertEquals(1, cursor.getCount());
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+            if (db != null) {
+                db.close();
+            }
+        }
     }
 
     /**
@@ -53,5 +99,53 @@
      */
     public void testEnsurePrivateDataNotExist() throws IOException {
         assertFalse(getContext().getFileStreamPath(PRIVATE_FILE_NAME).exists());
+
+        assertPreferencesDataDoesNotExist();
+        assertDatabaseDataDoesNotExist();
+    }
+
+    private void assertPreferencesDataDoesNotExist() {
+        SharedPreferences prefs = mContext.getSharedPreferences(PREFERENCES_FILE_NAME, 0);
+        assertNull(prefs.getString(PREFERENCE_KEY, null));
+    }
+
+    private void assertDatabaseDataDoesNotExist() {
+        SQLiteDatabase db = null;
+        Cursor cursor = null;
+        try {
+            db = new TestDatabaseOpenHelper(mContext).getWritableDatabase();
+            cursor = db.query(DB_TABLE_NAME, new String[] {DB_COLUMN},
+                    null, null, null, null, null);
+            assertEquals(0, cursor.getCount());
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+            if (db != null) {
+                db.close();
+            }
+        }
+    }
+
+    static class TestDatabaseOpenHelper extends SQLiteOpenHelper {
+
+        static final String _ID = "_id";
+
+        public TestDatabaseOpenHelper(Context context) {
+            super(context, "test.db", null, 1337);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + DB_TABLE_NAME + " ("
+                    + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + DB_COLUMN + " TEXT);");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE_NAME);
+            onCreate(db);
+        }
     }
 }
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 07ee067..57c5c31 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -21,6 +21,7 @@
 import dalvik.annotation.TestTargetNew;
 
 import android.app.SearchManager;
+import android.content.ContentUris;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -244,4 +245,70 @@
         assertCanBeHandled(new Intent(Settings.ACTION_WIFI_SETTINGS));
         assertCanBeHandled(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
     }
+
+    /**
+     * Test add event in calendar
+     */
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "Intent",
+        args = {java.lang.String.class}
+    )
+    public void testCalendarAddAppointment() {
+        Intent addAppointmentIntent = new Intent(Intent.ACTION_EDIT);
+        addAppointmentIntent.setType("vnd.android.cursor.item/event");
+        assertCanBeHandled(addAppointmentIntent);
+    }
+
+    /**
+     * Test view call logs
+     */
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "Intent",
+        args = {java.lang.String.class}
+    )
+    public void testContactsCallLogs() {
+        PackageManager packageManager = mContext.getPackageManager();
+        if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Intent intent = new Intent(Intent.ACTION_VIEW);
+            intent.setType("vnd.android.cursor.dir/calls");
+            assertCanBeHandled(intent);
+        }
+    }
+
+    /**
+     * Test view music playback
+     */
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "Intent",
+        args = {java.lang.String.class}
+    )
+    public void testMusicPlayback() {
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.setDataAndType(ContentUris.withAppendedId(
+                MediaStore.Audio.Media.INTERNAL_CONTENT_URI, 1), "audio/*");
+        assertCanBeHandled(intent);
+    }
+
+    /**
+     * Test launch inbox view of Mms application
+     */
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "Intent",
+        args = {java.lang.String.class}
+    )
+    public void testViewMessageInbox() {
+        PackageManager packageManager = mContext.getPackageManager();
+        if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Intent intent = new Intent(Intent.ACTION_MAIN);
+            intent.setType("vnd.android.cursor.dir/mms");
+            assertCanBeHandled(intent);
+
+            intent.setType("vnd.android-dir/mms-sms");
+            assertCanBeHandled(intent);
+        }
+    }
 }
diff --git a/tests/tests/content/src/android/content/cts/ContentQueryMapTest.java b/tests/tests/content/src/android/content/cts/ContentQueryMapTest.java
index d5d9666..ecb1c05 100644
--- a/tests/tests/content/src/android/content/cts/ContentQueryMapTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentQueryMapTest.java
@@ -263,9 +263,16 @@
             public void run() {
                 Looper.prepare();
                 mContentQueryMap.setKeepUpdated(true);
+                synchronized (ContentQueryMapTest.this) {
+                    //listener is ready, release the sender thread
+                    ContentQueryMapTest.this.notify();
+                }
                 Looper.loop();
             }
         }).start();
+        synchronized (this) {
+            wait(TEST_TIME_OUT);
+        }//wait the listener to be ready before launching onChange event
 
         // insert NAME3 and VALUE3
         values = new ContentValues();
@@ -285,9 +292,16 @@
             public void run() {
                 Looper.prepare();
                 mContentQueryMap.setKeepUpdated(false);
+                synchronized (ContentQueryMapTest.this) {
+                    //listener is ready, release the sender thread
+                    ContentQueryMapTest.this.notify();
+                }
                 Looper.loop();
             }
         }).start();
+        synchronized (this) {
+            wait(TEST_TIME_OUT);
+        }//wait the listener to be ready before launching onChange event
         // update NAME3 and VALUE3
         values = new ContentValues();
         values.put(DummyProvider.NAME, NAME0);